dimsum-e2e-tests 3.70.0-next.7 → 3.70.0-next.71

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.
Files changed (297) hide show
  1. package/CHANGELOG.md +1079 -721
  2. package/ds-accordion/DSAccordion.visual.spec.js +6 -0
  3. package/ds-accordion/DSAccordionCO.js +15 -3
  4. package/ds-accordion/QA_NOTES.md +105 -0
  5. package/ds-accordion/controlled/DSAccordion.controlled.func.spec.js +23 -0
  6. package/ds-accordion/header-structure/DSAccordion.header-structure.func.spec.js +65 -0
  7. package/ds-accordion/input-inside/DSAccordion.input-inside.func.spec.js +19 -0
  8. package/ds-apppicker/DSAppPickerCO.js +101 -3
  9. package/ds-apppicker/aria-pattern/DSAppPicker.aria-pattern.func.spec.js +100 -0
  10. package/ds-apppicker/basic/DSAppPicker.basic.keyboard-nav.func.spec.js +18 -7
  11. package/ds-apppicker/closeAfterSelection/DSAppPicker.closeAfterSelection.func.spec.js +1 -1
  12. package/ds-apppicker/custom-trigger-focus/DSAppPicker.custom-trigger-focus.func.spec.js +82 -0
  13. package/ds-apppicker/label-expansion-dismissal/DSAppPicker.label-expansion-dismissal.visual.spec.js +108 -0
  14. package/ds-apppicker/reflow/DSAppPicker.reflow.func.spec.js +32 -0
  15. package/ds-apppicker/reflow/DSAppPicker.reflow.visual.spec.js +5 -6
  16. package/ds-apppicker/truncation/DSAppPicker.truncation.visual.spec.js +5 -9
  17. package/ds-autocomplete/DSAutocomplete.visual.spec.js +34 -0
  18. package/ds-autocomplete/DSAutocompleteCO.js +36 -1
  19. package/ds-autocomplete/aria-busy-loading/DSAutocomplete.aria-busy-loading.axe-core.func.spec.js +50 -0
  20. package/ds-autocomplete/aria-busy-loading/DSAutocomplete.aria-busy-loading.func.spec.js +122 -0
  21. package/ds-autocomplete/aria-busy-loading/DSAutocomplete.aria-busy-loading.visual.spec.js +48 -0
  22. package/ds-autocomplete/slots/DSAutocomplete.slots.func.spec.js +6 -1
  23. package/ds-banner/DSBanner.text-resize.visual.spec.js +5 -2
  24. package/ds-banner/DSBannerCO.js +4 -0
  25. package/ds-button-v3/DSButtonV3.aria-disabled-attribute.func.spec.js +33 -0
  26. package/ds-button-v3/DSButtonV3CO.js +10 -0
  27. package/ds-button-v3/theme-font/DSButtonV3.theme-font.func.spec.js +30 -0
  28. package/ds-card/DSCard.cardv2_v1.func.spec.js +54 -0
  29. package/ds-card/DSCard.cardv2_v1.visual.spec.js +29 -0
  30. package/ds-card/DSCardCO.js +50 -0
  31. package/ds-card/detail-slots/DSCard.detail-slots.axe-core.func.spec.js +29 -0
  32. package/ds-card/detail-slots/DSCard.detail-slots.func.spec.js +72 -0
  33. package/ds-card/detail-slots/DSCard.detail-slots.visual.spec.js +19 -0
  34. package/ds-card-v3/DSCardV3CO.js +93 -1
  35. package/ds-card-v3/accordion/DSCardV3.accordion-aria-structure.func.spec.js +41 -0
  36. package/ds-card-v3/accordion/DSCardV3.accordion-aria.keyboard.func.spec.js +49 -0
  37. package/ds-card-v3/accordion/DSCardV3.accordion.axe-core.func.spec.js +28 -0
  38. package/ds-card-v3/accordion/DSCardV3.accordion.visual.spec.js +4 -6
  39. package/ds-card-v3/action/DSCardV3.action.axe-core.func.spec.js +24 -0
  40. package/ds-card-v3/action/DSCardV3.action.func.spec.js +53 -0
  41. package/ds-card-v3/action/DSCardV3.action.visual.spec.js +28 -0
  42. package/ds-card-v3/drag-n-drop/DSCardV3.DnD.axe-core.func.spec.js +42 -0
  43. package/ds-card-v3/drag-n-drop/DSCardV3.DnD.func.spec.js +129 -0
  44. package/ds-card-v3/drag-n-drop/DSCardV3.DnD.reorder.func.spec.js +73 -0
  45. package/ds-card-v3/drag-n-drop/DSCardV3.DnD.visual.spec.js +5 -12
  46. package/ds-card-v3/global-attributes/DSCardV3.global-attributes.axe-core.func.spec.js +33 -0
  47. package/ds-card-v3/global-attributes/DSCardV3.global-attributes.visual.spec.js +20 -0
  48. package/ds-card-v3/multi-select/DSCardV3.multi-select.aria-grouping.func.spec.js +24 -0
  49. package/ds-card-v3/multi-select/DSCardV3.multiselect.axe-core.func.spec.js +47 -0
  50. package/ds-card-v3/multi-select/DSCardV3.multiselect.keyboard.func.spec.js +65 -0
  51. package/ds-card-v3/multi-select/DSCardV3.multiselect.visual.spec.js +17 -0
  52. package/ds-card-v3/multiple-action/DSCardV3.multiple-action.axe-core.func.spec.js +35 -0
  53. package/ds-card-v3/multiple-action/DSCardV3.multiple-action.func.spec.js +53 -0
  54. package/ds-card-v3/multiple-action/DSCardV3.multiple-action.visual.spec.js +18 -0
  55. package/ds-card-v3/multiple-control/DSCardV3.multi-control.axe-core.func.spec.js +34 -0
  56. package/ds-card-v3/multiple-control/DSCardV3.multi-control.func.spec.js +26 -0
  57. package/ds-card-v3/multiple-control/DSCardV3.multi-control.visual.spec.js +29 -0
  58. package/ds-card-v3/no-action/DSCardV3.no-action.axe-core.func.spec.js +22 -0
  59. package/ds-card-v3/no-action/DSCardV3.no-action.func.spec.js +23 -0
  60. package/ds-card-v3/no-action/DSCardV3.no-action.visual.spec.js +15 -0
  61. package/ds-card-v3/notification-badges/DSCardV3.notification-badges.axe-core.func.spec.js +33 -0
  62. package/ds-card-v3/notification-badges/DSCardV3.notification-badges.func.spec.js +19 -0
  63. package/ds-card-v3/notification-badges/DSCardV3.notification-badges.visual.spec.js +28 -0
  64. package/ds-card-v3/reflow/DSCardV3.reflow.axe-core.func.spec.js +28 -0
  65. package/ds-card-v3/reflow/DSCardV3.reflow.func.spec.js +36 -0
  66. package/ds-card-v3/reflow/DSCardV3.reflow.visual.spec.js +3 -2
  67. package/ds-card-v3/single-select/DSCardV3.single-select.aria-grouping.func.spec.js +24 -0
  68. package/ds-card-v3/single-select/DSCardV3.single-select.axe-core.func.spec.js +37 -0
  69. package/ds-card-v3/single-select/DSCardV3.single-select.visual.spec.js +1 -2
  70. package/ds-card-v3/slots/DSCardV3.slots.visual.spec.js +1 -2
  71. package/ds-card-v3/variant-accented/DSCardV3.variant-accented.axe-core.func.spec.js +45 -0
  72. package/ds-card-v3/variant-accented/DSCardV3.variant-accented.func.spec.js +28 -0
  73. package/ds-card-v3/variant-accented/DSCardV3.variant-accented.visual.spec.js +35 -0
  74. package/ds-card-v3/variant-accented-disabled/DSCardV3.variant-accented-disabled.axe-core.func.spec.js +35 -0
  75. package/ds-card-v3/variant-accented-disabled/DSCardV3.variant-accented-disabled.func.spec.js +53 -0
  76. package/ds-card-v3/variant-accented-disabled/DSCardV3.variant-accented-disabled.visual.spec.js +28 -0
  77. package/ds-card-v3/variant-disabled/DSCardV3.variant-disabled.axe-core.func.spec.js +22 -0
  78. package/ds-card-v3/variant-disabled/DSCardV3.variant-disabled.func.spec.js +61 -0
  79. package/ds-card-v3/variant-disabled/DSCardV3.variant-disabled.visual.spec.js +20 -0
  80. package/ds-card-v3/variant-disabled/DSCardV3.variantDisabled-non-interactive.func.spec.js +25 -0
  81. package/ds-chat/DSChat.axe-core.func.spec.js +2 -2
  82. package/ds-chat/DSChat.visual.spec.js +4 -4
  83. package/ds-chat/DSChatCO.js +18 -24
  84. package/ds-chat/bubbles/slots/DSChatBubble.slots.axe-core.func.spec.js +24 -0
  85. package/ds-chat/bubbles/slots/DSChatBubble.slots.func.spec.js +49 -0
  86. package/ds-chat/bubbles/slots/DSChatBubble.slots.visual.spec.js +25 -0
  87. package/ds-chat/card/slots/DSChatCard.slots.axe-core.func.spec.js +24 -0
  88. package/ds-chat/card/slots/DSChatCard.slots.func.spec.js +47 -0
  89. package/ds-chat/card/slots/DSChatCard.slots.visual.spec.js +18 -0
  90. package/ds-chat/card/truncated-text/DSChatCard.truncated-text.func.spec.js +32 -0
  91. package/ds-chat/card/truncated-text/DSChatCard.truncated-text.visual.spec.js +26 -0
  92. package/ds-chat/card/with-notification-badges/DSChatCard.with-notification-badges.axe-core.func.spec.js +23 -0
  93. package/ds-chat/card/with-notification-badges/DSChatCard.with-notification-badges.visual.spec.js +17 -0
  94. package/ds-chat/components/BubbleCO.js +46 -3
  95. package/ds-chat/components/CardCO.js +75 -0
  96. package/ds-chat/components/ComposerCO.js +6 -6
  97. package/ds-chat/components/FloatingButtonCO.js +5 -3
  98. package/ds-chat/components/HeaderCO.js +2 -2
  99. package/ds-chat/components/TileCO.js +82 -0
  100. package/ds-chat/components/index.js +3 -2
  101. package/ds-chat/floatingbutton/DSChat-floating-button.visual.spec.js +1 -1
  102. package/ds-chat/loadmore/DSChat-loadmore.func.spec.js +1 -1
  103. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.axe-core.func.spec.js +2 -2
  104. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.func.spec.js +1 -1
  105. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.visual.spec.js +2 -2
  106. package/{ds-chat-tile → ds-chat/tile}/aria-disabled/DSChat-tile.aria-disabled.axe-core.func.spec.js +2 -2
  107. package/{ds-chat-tile → ds-chat/tile}/aria-disabled/DSChat-tile.aria-disabled.visual.spec.js +1 -1
  108. package/ds-chat/tile/slots/DSChatTile.slots.func.spec.js +53 -0
  109. package/ds-chat/tile/slots/DSChatTile.slots.visual.spec.js +18 -0
  110. package/ds-chip/label-expansion-dismissal/DSChip.label-expansion-dismissal.visual.spec.js +84 -0
  111. package/ds-controlled-form/ds-combobox/creatable/DSCombobox.creatable-tooltip.func.spec.js +47 -0
  112. package/ds-controlled-form/ds-combobox/creatable/DSCombobox.creatable.visual.spec.js +12 -21
  113. package/ds-controlled-form/ds-combobox/disabled/DSCombobox.disabled.visual.spec.js +6 -1
  114. package/ds-controlled-form/ds-controlled-checkbox/Basic/DSControlledCheckbox.axe-core.basic.func.spec.js +4 -4
  115. package/ds-controlled-form/ds-controlled-checkbox/Basic/DSControlledCheckbox.basic.visual.spec.js +56 -0
  116. package/ds-controlled-form/ds-controlled-checkbox/DSControlledCheckboxCO.js +54 -1
  117. package/ds-controlled-form/ds-controlled-checkbox/Disabled/DSControlledCheckbox.axe-core.disabled.func.spec.js +1 -1
  118. package/ds-controlled-form/ds-controlled-checkbox/Disabled/DSControlledCheckbox.disabled.visual.spec.js +1 -1
  119. package/ds-controlled-form/ds-controlled-checkbox/HasError/DSControlledCheckbox.axe-core.hasError.func.spec.js +4 -4
  120. package/ds-controlled-form/ds-controlled-checkbox/HasError/DSControlledCheckbox.has-error.visual.spec.js +71 -1
  121. package/ds-controlled-form/ds-controlled-checkbox/Mixed/DSControlledCheckbox.axe-core.mixed.func.spec.js +4 -4
  122. package/ds-controlled-form/ds-controlled-checkbox/Mixed/DSControlledCheckbox.mixed.visual.spec.js +1 -1
  123. package/ds-controlled-form/ds-controlled-checkbox/ReadOnly/DSControlledCheckbox.axe-core.read-only.func.spec.js +3 -3
  124. package/ds-controlled-form/ds-controlled-checkbox/ReadOnly/DSControlledCheckbox.read-only.visual.spec.js +1 -1
  125. package/ds-controlled-form/ds-controlled-checkbox/WithTooltip/DSControlledCheckbox.axe-core.with-tooltip.func.spec.js +1 -1
  126. package/ds-controlled-form/ds-controlled-checkbox/WithTooltip/DSControlledCheckbox.with-tooltip.visual.spec.js +1 -3
  127. package/ds-controlled-form/ds-controlled-checkbox/WrapLabel/DSControlledCheckbox.axe-core.wrap-label.func.spec.js +1 -1
  128. package/ds-controlled-form/ds-controlled-checkbox/WrapLabel/DSControlledCheckbox.wrap-label.visual.spec.js +1 -1
  129. package/ds-controlled-form/ds-controlled-checkbox/aria-disabled/DSControlledCheckbox.aria-disabled.visual.spec.js +2 -6
  130. package/ds-controlled-form/ds-controlled-checkbox/aria-disabled/DSControlledCheckbox.axe-core.aria-disabled.func.spec.js +1 -1
  131. package/ds-controlled-form/ds-controlled-checkbox/slots/DSControlledCheckbox.slots.func.spec.js +78 -0
  132. package/ds-controlled-form/ds-controlled-checkbox/theme-font/DSControlledCheckbox.theme-font.func.spec.js +30 -0
  133. package/ds-controlled-form/ds-controlled-checkbox-group/DSControlledCheckboxGroup.axe-core.func.spec.js +4 -4
  134. package/ds-controlled-form/ds-controlled-checkbox-group/DSControlledCheckboxGroup.visual.spec.js +1 -1
  135. package/ds-controlled-form/ds-controlled-radio/DSControlledRadioCO.js +50 -1
  136. package/ds-controlled-form/ds-controlled-radio/aria-disabled/DSControlledRadio.aria-disabled.axe-core.func.spec.js +16 -2
  137. package/ds-controlled-form/ds-controlled-radio/aria-disabled/DSControlledRadio.aria-disabled.func.spec.js +37 -0
  138. package/ds-controlled-form/ds-controlled-radio/slots/DSControlledRadio.slots.func.spec.js +78 -0
  139. package/ds-controlled-form/ds-controlled-radio/theme-font/DSControlledRadio.theme-font.func.spec.js +30 -0
  140. package/ds-controlled-form/react-hook-form/ReactHook.func.spec.js +1 -3
  141. package/ds-data-table-async/DSDataTableCO.js +187 -10
  142. package/ds-data-table-async/basic/DSDataTable.basic.visual.spec.js +1 -1
  143. package/ds-data-table-async/components/FilterBarCO.js +7 -0
  144. package/ds-data-table-async/components/FiltersCO.js +1 -1
  145. package/ds-data-table-async/components/HeaderCO.js +37 -1
  146. package/ds-data-table-async/dnd/DSDataTable.dnd-keyboard-scroll.func.spec.js +51 -0
  147. package/ds-data-table-async/filter-menu-close/DSDataTable.filter-menu-close.func.spec.js +77 -0
  148. package/ds-data-table-async/filter-popover-boundary/DSDataTable.filter-popover-boundary.func.spec.js +98 -0
  149. package/ds-data-table-async/filters/DSDataTable.filters-creatable-active-descendant.func.spec.js +51 -0
  150. package/ds-data-table-async/filters/DSDataTable.filters-creatable.func.spec.js +55 -0
  151. package/ds-data-table-async/filters/DSDataTable.filters.axe-core.func.spec.js +11 -9
  152. package/ds-data-table-async/filtersV2/DSDataTable.filtersV2-creatablemultiselect.keyboard.func.spec.js +2 -2
  153. package/ds-data-table-async/filtersV2/DSDataTable.filtersV2-creatableselect.keyboard.func.spec.js +2 -2
  154. package/ds-data-table-async/filtersV2/DSDataTable.filtersV2.axe-core.func.spec.js +45 -29
  155. package/ds-data-table-async/filtersV2/pill-label/DSDataTable.pillLabel.axe-core.func.spec.js +23 -0
  156. package/ds-data-table-async/filtersV2/pill-label/DSDataTable.pillLabel.func.spec.js +50 -0
  157. package/ds-data-table-async/filtersV2/pill-label/DSDataTable.pillLabel.visual.spec.js +21 -0
  158. package/ds-data-table-async/header-affordances/DSDataTable.header-affordances.func.spec.js +92 -0
  159. package/ds-data-table-async/helpers/getInputSelection.js +6 -0
  160. package/ds-data-table-async/helpers/index.js +1 -0
  161. package/ds-data-table-async/keyboard-scroll/DSDataTable.keyboard-scroll.func.spec.js +39 -0
  162. package/ds-data-table-async/menubutton/DSDataTable.MenuButton.keyboard.func.spec.js +8 -7
  163. package/ds-data-table-async/menubutton/DSDataTable.MenuButton.mouse.func.spec.js +6 -7
  164. package/ds-data-table-async/pagination/DSDataTable.pagination.func.spec.js +3 -2
  165. package/ds-data-table-async/resizable/DSDataTable.resize-min-clamp.func.spec.js +72 -0
  166. package/ds-data-table-async/resizable/DSDataTable.resizerA11y.axe-core.func.spec.js +42 -0
  167. package/ds-data-table-async/resizable/DSDataTable.resizerA11y.func.spec.js +98 -0
  168. package/ds-data-table-async/textwrapping/DSDataTable.header-wrap-alignment.axe-core.func.spec.js +23 -0
  169. package/ds-data-table-async/textwrapping/DSDataTable.header-wrap-alignment.visual.spec.js +106 -0
  170. package/ds-data-table-async/textwrapping/DSDataTable.text-wrap-toolbar.visual.spec.js +27 -0
  171. package/ds-data-table-async/toggle-cell-focus/DSDataTable.toggle-cell-enter-focus.func.spec.js +31 -0
  172. package/ds-data-table-async/vissibility/DSDataTable.vissibility.visual.spec.js +2 -0
  173. package/ds-dataviz/DSDataViz.axis.visual.spec.js +1 -2
  174. package/ds-dataviz/DSDataViz.ticks.visual.spec.js +1 -2
  175. package/ds-dataviz/DSDataVizCO.js +2 -0
  176. package/ds-dataviz/axecore/DSDataViz.axis.axe-core.func.spec.js +1 -1
  177. package/ds-floating-context/DSFloatingContextCO.js +10 -0
  178. package/ds-floating-context/placement/DSFloatingContext.placement.visual.spec.js +48 -0
  179. package/ds-form-combobox-multi/DSComboboxMultiCO.js +36 -9
  180. package/ds-form-combobox-multi/aria-busy-loading/DSComboboxMulti.aria-busy-loading.axe-core.func.spec.js +55 -0
  181. package/ds-form-combobox-multi/aria-busy-loading/DSComboboxMulti.aria-busy-loading.func.spec.js +57 -0
  182. package/ds-form-combobox-multi/aria-disabled/DSComboboxMulti.aria-disabled.visual.spec.js +19 -2
  183. package/ds-form-combobox-multi/disabled/DSComboboxMulti.disabled.axe-core.func.spec.js +24 -0
  184. package/ds-form-combobox-multi/disabled/DSComboboxMulti.disabled.mouse.func.spec.js +0 -2
  185. package/ds-form-combobox-multi/disabled/DSComboboxMulti.disabled.visual.spec.js +22 -0
  186. package/ds-form-combobox-multi/grouped/DSComboboxMulti.grouped.visual.spec.js +42 -0
  187. package/ds-form-combobox-multi/inline/DSComboboxMulti.inline.visual.spec.js +21 -0
  188. package/ds-form-combobox-multi/pills/DSComboboxMulti.pills.func.spec.js +59 -0
  189. package/ds-form-combobox-multi/pills/DSComboboxMulti.pills.visual.spec.js +39 -0
  190. package/ds-form-combobox-multi/skeleton/DSComboboxMulti.skeleton.visual.spec.js +25 -0
  191. package/ds-form-combobox-multi/theme-font/DSComboboxMulti.theme-font.func.spec.js +38 -0
  192. package/ds-form-combobox-multi/with-tooltip/DSComboboxMulti.with-tooltip.axe-core.func.spec.js +39 -0
  193. package/ds-form-combobox-multi/with-tooltip/DSComboboxMulti.with-tooltip.func.spec.js +39 -0
  194. package/ds-form-combobox-multi/with-tooltip/DSComboboxMulti.with-tooltip.visual.spec.js +29 -0
  195. package/ds-form-combobox-single/DSComboboxSingleCO.js +25 -9
  196. package/ds-form-combobox-single/aria-busy-loading/DSComboboxSingle.aria-busy-loading.axe-core.func.spec.js +49 -0
  197. package/ds-form-combobox-single/aria-busy-loading/DSComboboxSingle.aria-busy-loading.func.spec.js +54 -0
  198. package/ds-form-combobox-single/aria-disabled/DSComboboxSingle.aria-disabled.visual.spec.js +18 -0
  199. package/ds-form-combobox-single/creatable/DSComboboxSingle.creatable.visual.spec.js +30 -0
  200. package/ds-form-combobox-single/disabled/DSComboboxSingle.disabled.axe-core.func.spec.js +24 -0
  201. package/ds-form-combobox-single/disabled/DSComboboxSingle.disabled.mouse.func.spec.js +0 -2
  202. package/ds-form-combobox-single/disabled/DSComboboxSingle.disabled.visual.spec.js +22 -0
  203. package/ds-form-combobox-single/grouped/DSComboboxSingle.grouped.visual.spec.js +45 -0
  204. package/ds-form-combobox-single/inline/DSComboboxSingle.inline.visual.spec.js +23 -0
  205. package/ds-form-combobox-single/skeleton/DSComboboxSingle.skeleton.visual.spec.js +25 -0
  206. package/ds-form-combobox-single/theme-font/DSComboboxSingle.theme-font.func.spec.js +34 -0
  207. package/ds-form-combobox-single/with-tooltip/DSComboboxSingle.with-tooltip.axe-core.func.spec.js +39 -0
  208. package/ds-form-combobox-single/with-tooltip/DSComboboxSingle.with-tooltip.func.spec.js +39 -0
  209. package/ds-form-combobox-single/with-tooltip/DSComboboxSingle.with-tooltip.visual.spec.js +29 -0
  210. package/ds-form-date-range-picker/DateRangePicker.axe-core.spec.js +5 -0
  211. package/ds-form-date-range-picker/DateRangePicker.functional.spec.js +80 -18
  212. package/ds-form-date-range-picker/DateRangePickerCO.js +19 -0
  213. package/ds-form-date-range-picker/date-segment-aria-labels/DateRangePicker.date-segment-aria-labels.func.spec.js +66 -0
  214. package/ds-form-date-range-picker/grouped-field-error-announcement/DateRangePicker.grouped-field-error-announcement.func.spec.js +59 -0
  215. package/ds-form-date-range-picker/picker-callbacks/DateRangePicker.picker-callbacks.func.spec.js +36 -0
  216. package/ds-form-date-time-picker/DSControlledDateTimePickerCO.js +7 -0
  217. package/ds-form-date-time-picker/date-time-full/DateTimeFull.axe-core.func.spec.js +8 -1
  218. package/ds-form-date-time-picker/date-time-full/DateTimePicker.DateTimeFull.visual.spec.js +9 -0
  219. package/ds-form-date-time-picker/partial-date-open-focus/DateTimePicker.partial-date-open-focus.func.spec.js +45 -0
  220. package/ds-form-native-select/NativeSelect.axe-core.func.spec.js +39 -0
  221. package/ds-form-native-select/NativeSelect.visual.spec.js +33 -0
  222. package/ds-form-native-select/NativeSelectCO.js +6 -0
  223. package/ds-form-native-select/option-selection/NativeSelect.option-selection.func.spec.js +25 -0
  224. package/ds-form-toggle/DSToggle.func.spec.js +20 -23
  225. package/ds-form-toggle/DSToggleCO.js +11 -2
  226. package/ds-global-header/GlobalHeader.announcements.func.spec.js +27 -0
  227. package/ds-global-header/GlobalHeader.axe-core.func.spec.js +15 -15
  228. package/ds-global-header/GlobalHeader.func.spec.js +70 -1
  229. package/ds-global-header/GlobalHeaderCO.js +120 -2
  230. package/ds-global-header/app-picker-passthrough/GlobalHeader.app-picker-passthrough.func.spec.js +113 -0
  231. package/ds-global-header/popup-menu-focus/GlobalHeader.popup-menu-focus.func.spec.js +63 -0
  232. package/ds-global-header/popup-menu-slots/GlobalHeader.popup-menu-slots.func.spec.js +70 -0
  233. package/ds-global-header/search-toggle-slots/GlobalHeader.search-toggle-slots.func.spec.js +118 -0
  234. package/ds-global-header/toolbar-item-attributes/GlobalHeader.toolbar-item-attributes.func.spec.js +53 -0
  235. package/ds-grid/DSGridCO.js +20 -0
  236. package/ds-grid/layout-mode/DSGrid.layout-mode.func.spec.js +51 -0
  237. package/ds-grid/layout-mode/DSGrid.layout-mode.visual.spec.js +22 -0
  238. package/ds-hooks/DSHook.UseFontSizeMedia.visual.spec.js +5 -2
  239. package/ds-hooks/DSHook.usetree.func.spec.js +3 -2
  240. package/ds-hooks/DSHookCO.js +56 -23
  241. package/ds-hooks/useFocusStack/DSHook.useFocusStack.func.spec.js +83 -0
  242. package/ds-hooks/useFocusTrap/UseFocusTrapCO.js +2 -0
  243. package/ds-hooks/useFocusTrap/UseFocusTrapToggle.func.spec.js +48 -0
  244. package/ds-hooks/useMask/Number/UseNumberMask.axe-core.func.spec.js +48 -0
  245. package/ds-menu-button/DSMenuButtonCO.js +23 -0
  246. package/ds-menu-button/slots/DSMenuButton.slots.axe-core.func.spec.js +28 -0
  247. package/ds-menu-button/slots/DSMenuButton.slots.func.spec.js +59 -0
  248. package/ds-menu-button/slots/DSMenuButton.slots.visual.spec.js +26 -0
  249. package/ds-modal-slide/ModalSlideCO.js +7 -0
  250. package/ds-modal-slide/custom-header/ModalSlide.customHeader.focusRing.visual.spec.js +2 -1
  251. package/ds-modal-slide/heading-level/ModalSlide.headingLevel.axe-core.func.spec.js +25 -0
  252. package/ds-modal-slide/heading-level/ModalSlide.headingLevel.func.spec.js +25 -0
  253. package/ds-modal-slide/slots/ModalSlide.slots.func.spec.js +18 -0
  254. package/ds-notification-badge/DSNotificationBadge.visual.spec.js +17 -20
  255. package/ds-page-layout/PageLayoutCO.js +4 -4
  256. package/ds-pills-v2/DSPillsV2CO.js +12 -0
  257. package/ds-pills-v2/apply-aria-disabled/DSPills.applyAriaDisabled.func.spec.js +53 -0
  258. package/ds-pills-v2/apply-aria-disabled/DSPills.applyAriaDisabled.visual.spec.js +26 -0
  259. package/ds-pills-v2/disabled/DSPills.disabled.func.spec.js +53 -0
  260. package/ds-pills-v2/disabled/DSPills.disabled.visual.spec.js +33 -0
  261. package/ds-progress-indicator/DSProgressIndicator.axe-core.func.spec.js +2 -0
  262. package/ds-progress-indicator/DSProgressIndicatorCO.js +1 -1
  263. package/ds-query-builder/DSQueryBuilder.visual.spec.js +6 -6
  264. package/ds-shuttle-v2/DSShuttleV2CO.js +15 -1
  265. package/ds-shuttle-v2/breadcrumb-a11y/DSShuttleV2.breadcrumb-a11y.func.spec.js +43 -0
  266. package/ds-shuttle-v2/explicit-selection-ui/DSShuttleV2.explicit-selection-ui.func.spec.js +37 -0
  267. package/ds-shuttle-v2/explicit-selection-ui/DSShuttleV2.explicit-selection-ui.visual.spec.js +30 -0
  268. package/ds-shuttle-v2/extra/DSShuttleV2.extra.visual.spec.js +8 -3
  269. package/ds-shuttle-v2/items/DSShuttleV2.items.func.spec.js +4 -2
  270. package/ds-shuttle-v2/skipped/DSShuttleV2.extra.axe-core.skipped.js +1 -1
  271. package/ds-shuttle-v2/skipped/DSShuttleV2.filter.axe-core.skipped.js +1 -1
  272. package/ds-shuttle-v2/skipped/DSShuttleV2.globalcheckbox.axe-core.skipped.js +1 -1
  273. package/ds-shuttle-v2/skipped/DSShuttleV2.items.axe-core.skipped.js +3 -3
  274. package/ds-shuttle-v2/skipped/DSShuttleV2.skipped.js +5 -5
  275. package/ds-slider-v2/DSSliderV2.func.spec.js +36 -25
  276. package/ds-slider-v2/DSSliderV2CO.js +10 -0
  277. package/ds-slider-v2/min-range/DSSliderV2.min-range.func.spec.js +69 -0
  278. package/ds-tab-button/DSTabButton.func.spec.js +1 -1
  279. package/ds-tabs/DSTabsCO.js +4 -0
  280. package/ds-tabs/notification-badge/DSTabs.notification-badge.axe-core.func.spec.js +28 -0
  281. package/ds-tabs/notification-badge/DSTabs.notification-badge.func.spec.js +51 -0
  282. package/ds-tooltip-v3/DSTooltipV3CO.js +21 -0
  283. package/ds-tooltip-v3/aria-tooltip-pattern/DSTooltipV3.aria-tooltip-pattern.axe-core.func.spec.js +23 -0
  284. package/ds-tooltip-v3/aria-tooltip-pattern/DSTooltipV3.aria-tooltip-pattern.func.spec.js +29 -0
  285. package/ds-tooltip-v3/dialog/DSTooltipV3.dialog.func.spec.js +45 -0
  286. package/ds-tooltip-v3/dialog/DSTooltipV3.dialog.visual.spec.js +29 -0
  287. package/ds-treeview/DSTreeViewCO.js +23 -0
  288. package/ds-treeview/dragAndDrop/TreeView-dnd_keyboard.func.spec.js +96 -0
  289. package/ds-typography/DSTypographyCO.js +10 -0
  290. package/ds-typography/theme-font/DSTypography.theme-font.func.spec.js +30 -0
  291. package/package.json +150 -153
  292. package/paths.js +16 -6
  293. package/ds-card-v3/disabled/DSCardV3.disabled.visual.spec.js +0 -17
  294. package/ds-chat-tile/TileCO.js +0 -35
  295. package/ds-hooks/DSHook.func.spec.js +0 -60
  296. package/ds-hooks/useFocusStack/DSHook.useFocusStack.skipped.js +0 -57
  297. package/ds-treeview/dragAndDrop/TreeView-dnd_mouse.func.spec.js +0 -61
@@ -81,6 +81,12 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
81
81
  if (errorOnGo) throw errorOnGo;
82
82
  });
83
83
  it('01: should display accordion with global height, not trimmed', async () => {
84
+ const addRow = await $('[data-testid="add-row"]');
85
+ await addRow.click();
86
+ await addRow.click();
87
+ await addRow.click();
88
+ const content = await DSAccordionCO.getContents(0);
89
+ await content.waitForDisplayed();
84
90
  const snapshot = await browser.checkSnapshot(DSAccordionCO.snapshotPath('accordion-globalheight'));
85
91
  await expect(snapshot).toEqual(0);
86
92
  });
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable import/no-relative-packages */
2
- import { PATH_E2E_ACCORDION } from '../paths';
2
+ import { PATH_E2E_ACCORDION, PATH_E2E_ACCORDION_PITFALLS } from '../paths';
3
3
  import { PageObject, Urlbuilder, getElementByIndex } from '../helpers';
4
4
 
5
5
  export default class DSAccordionCO extends PageObject {
@@ -20,7 +20,9 @@ export default class DSAccordionCO extends PageObject {
20
20
 
21
21
  static tooltip = new Urlbuilder(PATH_E2E_ACCORDION, 'tooltip');
22
22
 
23
- static inputInside = new Urlbuilder(PATH_E2E_ACCORDION, 'PUI-9261-input-inside');
23
+ static inputInside = new Urlbuilder(PATH_E2E_ACCORDION, 'pui-9261-input-inside');
24
+
25
+ static controlled = new Urlbuilder(PATH_E2E_ACCORDION, 'controlled-test');
24
26
 
25
27
  static datepickerInside = new Urlbuilder(PATH_E2E_ACCORDION, 'actionable-within');
26
28
 
@@ -34,7 +36,7 @@ export default class DSAccordionCO extends PageObject {
34
36
 
35
37
  static keepContentURL = new Urlbuilder(PATH_E2E_ACCORDION, 'keep-content-mounted');
36
38
 
37
- static focusOnItemURL = new Urlbuilder(PATH_E2E_ACCORDION, 'focus-on-item');
39
+ static focusOnItemURL = new Urlbuilder(PATH_E2E_ACCORDION_PITFALLS, 'focus-on-item-test');
38
40
 
39
41
  static applyAriaDisabled = new Urlbuilder(PATH_E2E_ACCORDION, 'apply-aria-disabled-test');
40
42
 
@@ -100,11 +102,21 @@ export default class DSAccordionCO extends PageObject {
100
102
 
101
103
  static getToolbarByIndex = async (index) => getElementByIndex(this.getToolbarTriggers, index);
102
104
 
105
+ static async getToolbarMenuByIndex(index = 0) {
106
+ return $$('[data-testid="ds-menuitem-menu-item-wrapper"]')[index];
107
+ }
108
+
103
109
  static getAccordionItemHeaderContainers = async () => $$('[data-testid="ds-accordion-item-header-container"]');
104
110
 
105
111
  static getAccordionItemHeaderContainerByIndex = async (index) =>
106
112
  getElementByIndex(this.getAccordionItemHeaderContainers, index);
107
113
 
114
+ static getAccordionItemHeaderCustomActionsContainers = async () =>
115
+ $$('[data-testid="ds-accordion-item-header-custom-actions-container"]');
116
+
117
+ static getAccordionItemHeaderCustomActionsContainerByIndex = async (index) =>
118
+ getElementByIndex(this.getAccordionItemHeaderCustomActionsContainers, index);
119
+
108
120
  // slots
109
121
 
110
122
  static async getAccordionContainerSlotByIndex(index = 0) {
@@ -0,0 +1,105 @@
1
+ # QA Notes — ds-accordion E2E
2
+
3
+ Durable QA knowledge for the `accordion` suite. Carried over from the `ds-accordion-native` POC
4
+ notes ([PUI-18083](https://jira.elliemae.io/browse/PUI-18083)) when that parallel suite was removed —
5
+ see "Native migration" below.
6
+
7
+ ## Native migration ([PUI-18742](https://jira.elliemae.io/browse/PUI-18742))
8
+
9
+ `ds-accordion` now renders a native `<details>` / `<summary>` disclosure instead of the previous
10
+ WAI-ARIA button pattern. Public API, slot names and `data-testid` values are unchanged; only the DOM
11
+ engine changed. Full contract: [`stories/ds-accordion/docs/NativeDisclosureMigration.md`](../../stories/ds-accordion/docs/NativeDisclosureMigration.md).
12
+
13
+ ```html
14
+ <div data-testid="ds-accordion_item">
15
+ <details data-testid="ds-accordion-item-details">
16
+ <summary data-testid="ds-accordion_item-header" aria-expanded aria-controls="ds-accordion-content-0">
17
+ <div data-testid="ds-accordion-item-header-container">… chevron + title(s) …</div>
18
+ </summary>
19
+ <div data-testid="ds-accordion_item-content" role="region" aria-labelledby="ds-accordion-header-0">…</div>
20
+ </details>
21
+ <div data-testid="ds-accordion-item-header-custom-actions-container">… custom actions …</div>
22
+ </div>
23
+ ```
24
+
25
+ **What this changes for specs:**
26
+
27
+ - The trigger is a `<summary>`, **not** a `<button>`. `getAccordionHeader(i)` returns the `<summary>`.
28
+ - The heading container lives **inside** the summary (inverse of the pre-migration nesting).
29
+ - `role="heading"` + `aria-level` are **not** emitted by the component. They are opt-in per consumer
30
+ through the `dsAccordionItemHeaderContainer` slot prop. Only stories that set that prop
31
+ (e.g. `WithSecondaryTitleTest`, `AdvancedHeadingStructureCustomization`) expose heading semantics —
32
+ `HeaderControlExamplesTest` does not. Assert the role only on a story that opts in
33
+ (`role/DSAccordion.role-heading.func.spec.js`).
34
+ - Custom actions render as a **sibling of `<details>`**, outside the trigger. Nothing interactive is
35
+ nested inside the `<summary>`.
36
+ - `ds-accordion-item-details` is an additive slot/testid introduced by the migration.
37
+
38
+ The former `ds-accordion-native` E2E suite was deleted here — `ds-accordion` **is** the native engine
39
+ now, so the parity suite had no stories left to point at (`stories/ds-accordion-native` and
40
+ `PATH_E2E_ACCORDION_NATIVE` were removed in PUI-18742).
41
+
42
+ ## header-structure func — test 04 flaky "Login not displayed" (cloud)
43
+
44
+ **Status:** spec hardened (spec-only + one additive CO helper). Investigated 2026-07-02 on the native
45
+ suite; the same hardening now lives in `header-structure/DSAccordion.header-structure.func.spec.js`.
46
+
47
+ **Symptom:** in the cloud run (`E2E_BACKEND=cloud`, `BASE_URL`=NEXT/d3, Chrome-only) test
48
+ `04: toolbar trigger in custom actions should open dropdown menu on click` broke with
49
+ `element ("*=Login") still not displayed after 10000ms`. Only that browser runs it (the spec is
50
+ Chrome-guarded), so it surfaces as 1 broken.
51
+
52
+ **Not a defect.** Reproduced against NEXT/d3 at the SDK viewport (1920×1080): the click opens the
53
+ `DSDropdownMenuV2` (`dropdown-menu-listbox` + `ds-floating-wrapper-root` present), `Login` resolves to
54
+ a single visible `<p>`, not clipped by any overflow ancestor and not occluded (`elementFromPoint` at
55
+ its center returns the element), and it stays open at 3s. Selectors, story and package are correct.
56
+ Passed 100% locally, broke 100% in cloud → the delta is real-Chrome + BrowserStack +
57
+ `browser.maximizeWindow()` (cloud-only).
58
+
59
+ **Root cause:** the pattern "one-shot click on a toggle + `waitForDisplayed` on a deep descendant" is
60
+ fragile. If the click doesn't leave the menu open in that driver, the wait sits the full 10s on a menu
61
+ that never opened.
62
+
63
+ **Fix:** wait for the trigger to be clickable, click it, then assert the `DSDropdownMenuV2` item
64
+ wrapper (`getToolbarMenuByIndex` → `ds-menuitem-menu-item-wrapper`) is displayed _before_ checking the
65
+ first option, and tag-qualify the option selector as `p*=Login` (`DSTypography variant="b1"` renders a
66
+ `<p>`). The SDK's retries absorb residual flakiness. Optional broader mitigation: enable
67
+ `config.specFileRetries` in `wdio.config.mjs`.
68
+
69
+ ## input-inside func — `data-testid` is on the `<input>`, not a wrapper
70
+
71
+ `DSInputText` forwards `data-testid` through its global attributes straight onto `StyledInput`, i.e.
72
+ the `<input>` element. A descendant selector like `[data-testid="task-name"] input` matches nothing
73
+ and breaks on every browser. Target the testid directly.
74
+
75
+ ## Open defects from the native POC — re-verify against ds-accordion
76
+
77
+ These were logged against `ds-accordion-native` while it was a separate POC package. Now that
78
+ `ds-accordion` ships the native engine, **each needs re-verification against `ds-accordion`** before
79
+ being closed or re-pointed — they are listed here so the findings are not lost with the deleted suite,
80
+ not as confirmed `ds-accordion` defects.
81
+
82
+ | Ticket | Summary |
83
+ | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
+ | [PUI-18640](https://jira.elliemae.io/browse/PUI-18640) | Content-container slot did not apply style-props — `maxHeight`/`overflow` (scrollable-content) and padding `p` (XstyledpropsInContent) — the way pre-migration `ds-accordion` did. Breaking for consumers styling content via the slot. |
85
+ | [PUI-18641](https://jira.elliemae.io/browse/PUI-18641) | Default title behavior changed from truncate-with-tooltip to wrap. With `wrapLabel={false}` the title truncates but shows no tooltip on hover → full text unreadable. Backwards-incompatible default + readability gap. |
86
+ | [PUI-18642](https://jira.elliemae.io/browse/PUI-18642) | Arrow Icon visual spec violations (Accordion Draft v1.5.0): region width is not the spec'd 20px; when the title wraps the icon is center-aligned instead of top-aligned ("Fixed Top-aligned — Region A"). |
87
+ | [PUI-18695](https://jira.elliemae.io/browse/PUI-18695) | _Safari-only:_ Tab does not move focus between accordion headers after a click. Click-focus, focus ring and Enter all work; only Tab traversal is broken. Found by E2E visual PUI-14324 - 02 (Safari). |
88
+
89
+ Related upstream: [WebKit bug #319162](https://bugs.webkit.org/show_bug.cgi?id=319162) — in Safari,
90
+ tabbing away from a `<summary>` that contains nested elements after **mouse** activation does not
91
+ advance focus correctly. Keyboard-only navigation is unaffected. Unresolved upstream.
92
+
93
+ ## Known visual baseline note — slots (`PUI-15348 - 01`)
94
+
95
+ Percy flagged a ~0.05% diff: a small lavender box at the left of each "… Secondary" row. Not a
96
+ regression. `StyledHeading` moved from `display: contents` → `display: flex`; an element with
97
+ `display: contents` generates no box and therefore never paints its `background`, so the `SlotsTest`
98
+ story's lavender `item-heading` background was silently dropped before and paints now. Only visible in
99
+ that synthetic story (every slot painted a loud color). Re-approve the baseline if it resurfaces.
100
+
101
+ ---
102
+
103
+ _Historical detail (A/B/C/D divergence audit, Percy mechanism, run commands) lived in
104
+ `stories/ds-accordion-native/POC_FINDINGS.md`, removed in PUI-18742. Recover with
105
+ `git show 3468ca3ccb4^:stories/ds-accordion-native/POC_FINDINGS.md`._
@@ -0,0 +1,23 @@
1
+ import DSAccordionCO from '../DSAccordionCO';
2
+
3
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
4
+ // New coverage for the ControlledTest story (previously untested).
5
+ describe('PUI-18650 - Accordion, controlled -func', () => {
6
+ before('loading page', async () => {
7
+ const errorOnGo = await DSAccordionCO.controlled.go();
8
+ if (errorOnGo) throw errorOnGo;
9
+ });
10
+ it('01: single-open: opening another item collapses the previously open one', async () => {
11
+ await expect(await DSAccordionCO.getAccordionHeader(0)).toHaveAttribute('aria-expanded', 'true');
12
+ await (await DSAccordionCO.getAccordionHeader(1)).click();
13
+ await expect(await DSAccordionCO.getAccordionHeader(1)).toHaveAttribute('aria-expanded', 'true');
14
+ await expect(await DSAccordionCO.getAccordionHeader(0)).toHaveAttribute('aria-expanded', 'false');
15
+ });
16
+ it('02: multiple-open: opening two items keeps both expanded', async () => {
17
+ await (await DSAccordionCO.getAccordionHeader(3)).click();
18
+ await (await DSAccordionCO.getAccordionHeader(4)).click();
19
+ await expect(await DSAccordionCO.getAccordionHeader(3)).toHaveAttribute('aria-expanded', 'true');
20
+ await expect(await DSAccordionCO.getAccordionHeader(4)).toHaveAttribute('aria-expanded', 'true');
21
+ });
22
+ });
23
+ }
@@ -0,0 +1,65 @@
1
+ import DSAccordionCO from '../DSAccordionCO';
2
+
3
+ if (
4
+ (!browser.capabilities['ice:options'].isPhone &&
5
+ !browser.capabilities['ice:options'].isTablet &&
6
+ browser.capabilities.browserName === 'chrome') ||
7
+ browser.capabilities.browserName === 'Chrome'
8
+ ) {
9
+ // Structural coverage for custom actions living OUTSIDE the disclosure trigger.
10
+ // Originally written for PUI-17912 (custom actions moved out of the role="heading" container).
11
+ // PUI-18742 migrated ds-accordion to a native <details>/<summary> disclosure, which supersedes
12
+ // that fix: the <summary> IS the toggle, the heading container now sits INSIDE it, and heading
13
+ // semantics (role="heading" + aria-level) are opt-in per consumer via the
14
+ // dsAccordionItemHeaderContainer slot prop — see role/DSAccordion.role-heading.func.spec.js.
15
+ // The invariant that still matters here: nothing interactive is nested inside the trigger.
16
+ describe('PUI-18621 - DSAccordion:: heading container structure after renderCustomActions fix - func', () => {
17
+ before('loading page', async () => {
18
+ const errorOnGo = await DSAccordionCO.headerControls.go();
19
+ if (errorOnGo) throw errorOnGo;
20
+ });
21
+
22
+ it('01: summary trigger should wrap the heading container and no other interactive elements', async () => {
23
+ const trigger = await DSAccordionCO.getAccordionHeader(0);
24
+ await expect(await trigger.getTagName()).toBe('summary');
25
+
26
+ const headingContainer = await DSAccordionCO.getAccordionItemHeaderContainerByIndex(0);
27
+ await expect(headingContainer).toExist();
28
+
29
+ // The <summary> is the toggle itself, so no nested <button> may live inside it.
30
+ const buttonsInsideTrigger = await trigger.$$('button');
31
+ await expect(buttonsInsideTrigger.length).toBe(0);
32
+ });
33
+
34
+ it('02: custom actions container should exist outside the heading container', async () => {
35
+ const customActionsContainer = await DSAccordionCO.getAccordionItemHeaderCustomActionsContainerByIndex(0);
36
+ await expect(customActionsContainer).toExist();
37
+ });
38
+
39
+ it('03: action buttons in custom actions container should reflect correct enabled/disabled state', async () => {
40
+ const enabledContainer = await DSAccordionCO.getAccordionItemHeaderCustomActionsContainerByIndex(0);
41
+ const enabledButton = await enabledContainer.$('[data-testid="ds-button"]');
42
+ await expect(enabledButton).toBeDisplayed();
43
+ await expect(enabledButton).toBeEnabled();
44
+
45
+ const disabledContainer = await DSAccordionCO.getAccordionItemHeaderCustomActionsContainerByIndex(2);
46
+ const disabledButton = await disabledContainer.$('[data-testid="ds-button"]');
47
+ await expect(disabledButton).toBeDisplayed();
48
+ await expect(disabledButton).not.toBeEnabled();
49
+ });
50
+
51
+ it('04: toolbar trigger in custom actions should open dropdown menu on click', async () => {
52
+ // Hardened after the cloud-only "Login not displayed" flake (see QA_NOTES.md): wait for the
53
+ // trigger to be clickable, then assert the DSDropdownMenuV2 item wrapper is displayed before
54
+ // reaching for the option, so a menu that never opened fails fast instead of burning the
55
+ // 10s waitForDisplayed. `p*=Login` is tag-qualified — DSTypography variant="b1" renders a <p>.
56
+ const toolbar = await DSAccordionCO.getToolbarByIndex(0);
57
+ await toolbar.waitForClickable({ timeout: 10000 });
58
+ await toolbar.click();
59
+ const menu = await DSAccordionCO.getToolbarMenuByIndex(0);
60
+ await expect(menu).toBeDisplayed();
61
+ const firstMenuOption = await $('p*=Login');
62
+ await expect(firstMenuOption).toBeDisplayed();
63
+ });
64
+ });
65
+ }
@@ -0,0 +1,19 @@
1
+ import DSAccordionCO from '../DSAccordionCO';
2
+
3
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
4
+ // New coverage for the PUI9261InputInside story (previously untested).
5
+ describe('PUI-18651 - Accordion, input inside content -func', () => {
6
+ before('loading page', async () => {
7
+ const errorOnGo = await DSAccordionCO.inputInside.go();
8
+ if (errorOnGo) throw errorOnGo;
9
+ });
10
+ it('01: should type into an input rendered inside the open accordion item', async () => {
11
+ // DSInputText forwards `data-testid` through its global attributes onto the <input> itself
12
+ // (StyledInput), not onto the wrapper — so the testid IS the input, never its ancestor.
13
+ const input = await $('[data-testid="task-name"]');
14
+ await input.waitForDisplayed();
15
+ await input.setValue('Test task');
16
+ await expect(input).toHaveValue('Test task');
17
+ });
18
+ });
19
+ }
@@ -18,14 +18,27 @@ export default class DSAppPickerCO extends PageObject {
18
18
 
19
19
  static reflowURL = new Urlbuilder(`${PATH_E2E_APP_PICKER}`, 'reflow-test');
20
20
 
21
+ // PUI-18647 — the two custom-trigger APIs side by side. Storybook kebab-cases the
22
+ // `PUI18647CustomTriggers...` export with a hyphen after the prefix, hence `pui-18647`.
23
+ static customTriggerFocusURL = new Urlbuilder(
24
+ `${PATH_E2E_APP_PICKER}`,
25
+ 'pui-18647-custom-triggers-focus-parity-with-deprecated',
26
+ );
27
+
21
28
  // Snapshots
22
29
  static snapshotPath(example = 'basic') {
23
30
  return PageObject.getSnapshotPathBuilder('AppPicker', example);
24
31
  }
25
32
 
26
33
  // selectors
34
+ // Anchored on data-testid, NOT on the `#app-picker__button` id this used to select. The trigger's
35
+ // `id` is the per-instance dialog label id the dialog's aria-labelledby resolves to
36
+ // (`ds-app-picker-<uid>-dialog-trigger-btn`), deliberately uid-based so several pickers can
37
+ // coexist — documented under "Multiple pickers on one page" in the AccessibilityBehavior docs,
38
+ // which points automation at either a `data-testid` or an `id` prop passed to DSAppPicker.
39
+ // data-testid is the QA-stability-protected identifier, so it is the correct anchor here.
27
40
  static async getOpenAppPicker() {
28
- return $(`#app-picker__button`);
41
+ return $('[data-testid="app-picker__button"]');
29
42
  }
30
43
 
31
44
  static getChips = async () => $$('[data-testid="app-picker__chip"]');
@@ -51,12 +64,97 @@ export default class DSAppPickerCO extends PageObject {
51
64
  return $('[data-testid="ds-apppicker-root"]');
52
65
  }
53
66
 
67
+ // The floating layer that wraps the panel — carries role="dialog" + aria-labelledby. It sits two
68
+ // levels ABOVE the panel root and is portaled to document.body, so it is not reachable from the
69
+ // root selector.
70
+ static async getFloatingWrapper() {
71
+ return $('[data-testid="ds-apppicker-floating-wrapper"]');
72
+ }
73
+
74
+ // One per section (apps + customApps) — the ARIA group tying a section title to its chips.
75
+ static getGroups = async () => $$('[data-testid="ds-apppicker-group"]');
76
+
77
+ static getGroupByIndex = async (index) => getElementByIndex(this.getGroups, index);
78
+
79
+ static getTitles = async () => $$('[data-testid="ds-apppicker-title"]');
80
+
81
+ static getTitleByIndex = async (index) => getElementByIndex(this.getTitles, index);
82
+
83
+ // Full-width layout rows holding a section title or the separator — purely presentational.
84
+ static getRows = async () => $$('[data-testid="ds-apppicker-row"]');
85
+
86
+ static async openPanel() {
87
+ const trigger = await this.getOpenAppPicker();
88
+ await trigger.waitForDisplayed();
89
+ await trigger.click();
90
+ await (await this.getAppPickerRoot()).waitForDisplayed();
91
+ }
92
+
93
+ // Reads one value per element in a wdio element array. Element arrays in wdio 9 expose their own
94
+ // promise-returning `map`, so `Promise.all(list.map(fn))` is handed a Promise rather than an
95
+ // iterable and throws. `length` + index access behave like a plain array in every version, so the
96
+ // iteration is built from those instead.
97
+ static async collect(elements, read) {
98
+ return Promise.all(Array.from({ length: elements.length }, (_, index) => read(elements[index])));
99
+ }
100
+
101
+ // Measures every chip in the open panel and buckets them by vertical offset — one bucket per
102
+ // rendered grid row. Row membership is derived, not hardcoded: the 3-column grid reflows with
103
+ // viewport width and font size, so which chips share a row is a runtime fact.
104
+ static async getChipRowsGeometry() {
105
+ const chips = await this.getChips();
106
+ const measured = await DSAppPickerCO.collect(chips, async (chip) => {
107
+ const { y } = await chip.getLocation();
108
+ const { height } = await chip.getSize();
109
+ return { label: await chip.getAttribute('aria-label'), top: Math.round(y), height: Math.round(height) };
110
+ });
111
+
112
+ const rowsByTop = measured.reduce((acc, chip) => {
113
+ acc[chip.top] = [...(acc[chip.top] ?? []), chip];
114
+ return acc;
115
+ }, {});
116
+
117
+ return Object.values(rowsByTop).map(DSAppPickerCO.summariseChipRow);
118
+ }
119
+
120
+ // Reduces one measured row to the numbers a height assertion needs, plus a human-readable
121
+ // breakdown so a failure names the offending chips and their pixel heights.
122
+ static summariseChipRow(row) {
123
+ const heights = row.map((chip) => chip.height);
124
+ return {
125
+ chipCount: row.length,
126
+ tallest: Math.max(...heights),
127
+ shortest: Math.min(...heights),
128
+ breakdown: row.map((chip) => `${chip.label} (${chip.height}px)`).join(', '),
129
+ };
130
+ }
131
+
54
132
  static async getChipLabelByIndex(index) {
55
133
  return $$('[data-testid="ds-chip-label"]')[index];
56
134
  }
57
135
 
136
+ // Selection is exposed as `aria-current="true"`, not `aria-selected`. The chips are `role="button"`,
137
+ // which does not support `aria-selected` — PUI-17213/PUI-17860 (#8260) swapped it for `aria-current`
138
+ // plus the "X of Y" position announcement, signed off with the A11y SME.
139
+ // The attribute is omitted (not `false`) when unselected, so `getAttribute` resolves to null: compare
140
+ // the value instead of calling a string method on it, so an unselected chip returns false rather than
141
+ // throwing.
58
142
  static async isSelected(element) {
59
- return (await element.getAttribute('aria-selected')).includes('true');
143
+ return (await element.getAttribute('aria-current')) === 'true';
144
+ }
145
+
146
+ // PUI-18647 selectors
147
+
148
+ // The supported API: DSAppPicker hands the trigger renderer `innerRef` plus the internal handlers,
149
+ // so it can drive the first-app/selected-app focus logic on open.
150
+ static async getSupportedCustomTrigger() {
151
+ return $('[data-testid="pui18647-trigger-component"]');
152
+ }
153
+
154
+ // The deprecated API: `renderTrigger` receives only `ref`, so it cannot reach those handlers. It
155
+ // keeps its pre-existing behaviour by design — this is not a bug, it is the documented delta.
156
+ static async getDeprecatedCustomTrigger() {
157
+ return $('[data-testid="pui18647-render-trigger"]');
60
158
  }
61
159
 
62
160
  // Slots
@@ -78,6 +176,6 @@ export default class DSAppPickerCO extends PageObject {
78
176
  }
79
177
 
80
178
  static async getTitleSlotByIndex(index = 0) {
81
- return $$('[data-dimsum-slot="dsApppickerTitle"]')[index];
179
+ return $$('[data-dimsum-parent-slot="dsApppickerTitle"]')[index];
82
180
  }
83
181
  }
@@ -0,0 +1,100 @@
1
+ import DSAppPickerCO from '../DSAppPickerCO';
2
+
3
+ // Tests for the fix introduced in PUI-17213 (Roles and Pattern Mismatch): the AppPicker was built
4
+ // as a menu but carried neither the menu nor the dialog ARIA contract. It is now a dialog —
5
+ // aria-haspopup="dialog" + no aria-expanded on the trigger, role="dialog" + aria-labelledby on the
6
+ // floating layer, one role="group" per section labelled by its <h3> title, presentational layout
7
+ // rows, and chips left with their native button semantics instead of role="option".
8
+ //
9
+ // Every id in this component is namespaced by a per-instance uid, so the assertions are relational
10
+ // (the dialog's aria-labelledby resolves to the trigger's id) rather than matching literal strings.
11
+ if (
12
+ (!browser.capabilities['ice:options'].isPhone &&
13
+ !browser.capabilities['ice:options'].isTablet &&
14
+ browser.capabilities.browserName === 'chrome') ||
15
+ browser.capabilities.browserName === 'Chrome'
16
+ ) {
17
+ describe('PUI-18911 - DSAppPicker:: dialog ARIA pattern roles and relationships - Func', () => {
18
+ before('loading page', async () => {
19
+ const errorOnGo = await DSAppPickerCO.basicURL.go();
20
+ if (errorOnGo) throw errorOnGo;
21
+ });
22
+
23
+ it('01: should expose the closed trigger as a dialog popup button', async () => {
24
+ const trigger = await DSAppPickerCO.getOpenAppPicker();
25
+ await trigger.waitForDisplayed();
26
+
27
+ await expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
28
+ await expect(trigger).toHaveAttribute('aria-label', 'Application picker');
29
+ // aria-expanded belongs to disclosure patterns; on a dialog popup it produces a conflicting
30
+ // announcement, so it must be absent both closed and open (re-checked in 02).
31
+ await expect(await trigger.getAttribute('aria-expanded')).toBe(null);
32
+ await expect(await trigger.getAttribute('id')).not.toBe(null);
33
+ });
34
+
35
+ it('02: should open a dialog whose accessible name comes from the trigger', async () => {
36
+ const trigger = await DSAppPickerCO.getOpenAppPicker();
37
+ await DSAppPickerCO.openPanel();
38
+
39
+ const dialog = await DSAppPickerCO.getFloatingWrapper();
40
+ await expect(dialog).toHaveAttribute('role', 'dialog');
41
+ // The dialog and the trigger share one accessible name: aria-labelledby points at the trigger.
42
+ await expect(await dialog.getAttribute('aria-labelledby')).toBe(await trigger.getAttribute('id'));
43
+ // The replaced aria-label="popup menu" must not have come back alongside aria-labelledby.
44
+ await expect(await dialog.getAttribute('aria-label')).toBe(null);
45
+
46
+ // The panel root is roleless (the former role="region" is gone), so it carries no name either.
47
+ const root = await DSAppPickerCO.getAppPickerRoot();
48
+ await expect(await root.getAttribute('role')).toBe(null);
49
+ await expect(await root.getAttribute('aria-label')).toBe(null);
50
+
51
+ await expect(await trigger.getAttribute('aria-expanded')).toBe(null);
52
+ });
53
+
54
+ it('03: should group each section and label it with its own h3 heading', async () => {
55
+ const groups = await DSAppPickerCO.getGroups();
56
+ const titles = await DSAppPickerCO.getTitles();
57
+ // The story renders apps + customApps, so both sections are present.
58
+ await expect(groups.length).toBe(2);
59
+ await expect(titles.length).toBe(2);
60
+
61
+ const mainGroup = await DSAppPickerCO.getGroupByIndex(0);
62
+ const mainTitle = await DSAppPickerCO.getTitleByIndex(0);
63
+ await expect(mainGroup).toHaveAttribute('role', 'group');
64
+ await expect(await mainGroup.getAttribute('aria-labelledby')).toBe(await mainTitle.getAttribute('id'));
65
+
66
+ const customGroup = await DSAppPickerCO.getGroupByIndex(1);
67
+ const customTitle = await DSAppPickerCO.getTitleByIndex(1);
68
+ await expect(customGroup).toHaveAttribute('role', 'group');
69
+ await expect(await customGroup.getAttribute('aria-labelledby')).toBe(await customTitle.getAttribute('id'));
70
+
71
+ // The titles stay real headings: role="presentation" would hide them from screen reader
72
+ // heading navigation in browse mode.
73
+ await expect(await mainTitle.getTagName()).toBe('h3');
74
+ await expect(await customTitle.getTagName()).toBe('h3');
75
+ await expect(await mainTitle.getAttribute('role')).toBe(null);
76
+ await expect(await customTitle.getAttribute('role')).toBe(null);
77
+ });
78
+
79
+ it('04: should keep layout rows presentational and chips as buttons', async () => {
80
+ // The full-row wrappers around the titles and the separator are layout only: role="group" was
81
+ // reserved for the real sections (03) and aria-hidden="true" would drop them from the tree
82
+ // instead of conveying them as presentation.
83
+ const rows = await DSAppPickerCO.getRows();
84
+ await expect(rows.length).toBeGreaterThan(0);
85
+ const rowRoles = await DSAppPickerCO.collect(rows, (row) => row.getAttribute('role'));
86
+ const rowAriaHidden = await DSAppPickerCO.collect(rows, (row) => row.getAttribute('aria-hidden'));
87
+ await expect(rowRoles.every((role) => role === null)).toBe(true);
88
+ await expect(rowAriaHidden.every((hidden) => hidden === null)).toBe(true);
89
+
90
+ // Chips keep their native button semantics inside the dialog — role="option" claimed a
91
+ // listbox parent that never existed.
92
+ const chips = await DSAppPickerCO.getChips();
93
+ await expect(chips.length).toBeGreaterThan(0);
94
+ const chipTags = await DSAppPickerCO.collect(chips, (chip) => chip.getTagName());
95
+ const chipRoles = await DSAppPickerCO.collect(chips, (chip) => chip.getAttribute('role'));
96
+ await expect(chipTags.every((tag) => tag === 'button')).toBe(true);
97
+ await expect(chipRoles.every((role) => role === 'button')).toBe(true);
98
+ });
99
+ });
100
+ }
@@ -1,11 +1,7 @@
1
1
  import { Key } from 'webdriverio';
2
2
  import DSAppPickerCO from '../DSAppPickerCO';
3
3
 
4
- if (
5
- !browser.capabilities['ice:options'].isPhone &&
6
- !browser.capabilities['ice:options'].isTablet &&
7
- browser.capabilities.browserName !== 'Safari'
8
- ) {
4
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
9
5
  describe('PUI-8030 - AppPicker:: Basic - keyboard nav func', () => {
10
6
  before('loading page', async () => {
11
7
  const errorOnGo = await DSAppPickerCO.basicURL.go();
@@ -34,12 +30,27 @@ if (
34
30
  const appPickerChip = await DSAppPickerCO.getChipByIndex(1);
35
31
  await expect(appPickerChip).toBeFocused();
36
32
  });
37
- it('05: should close the menu - Escape', async () => {
33
+ // PUI-17950 made Escape the dismissal mechanism for a chip's expanded label, satisfying the
34
+ // "Dismissible" clause of WCAG 2.1 AA 1.4.13. Escape on an open panel is therefore two-stage
35
+ // whenever the focused chip's label truncates: the first press dismisses the expansion, only
36
+ // the second reaches the dialog. Chip 1 here truncates, so both presses are needed. The
37
+ // dismissal is conditional, not blanket — on a chip whose label fits, Escape still closes the
38
+ // panel in a single press, so this is not a rule that can be applied by rote to every spec.
39
+ it('05: should dismiss the expanded chip label and keep the menu open - Escape', async () => {
40
+ const appPickerChip = await DSAppPickerCO.getChipByIndex(1);
41
+ expect(await appPickerChip.getAttribute('data-expanded')).toEqual('true');
42
+ await browser.keys(Key.Escape);
43
+ const appPicker = await DSAppPickerCO.getAppPickerRoot();
44
+ await expect(appPicker).toBeDisplayedInViewport();
45
+ await expect(appPickerChip).toBeFocused();
46
+ expect(await appPickerChip.getAttribute('data-expanded')).not.toEqual('true');
47
+ });
48
+ it('06: should close the menu - Escape', async () => {
38
49
  const openAppPickerBtn = await DSAppPickerCO.getOpenAppPicker();
39
50
  await browser.keys(Key.Escape);
40
51
  await expect(openAppPickerBtn).toBeFocused();
41
52
  });
42
- it('06: should reopen the menu and focus the first enabled chip - Space', async () => {
53
+ it('07: should reopen the menu and focus the first enabled chip - Space', async () => {
43
54
  await browser.keys(Key.Space);
44
55
  const appPicker = await DSAppPickerCO.getAppPickerRoot();
45
56
  const appPickerChip = await DSAppPickerCO.getChipByIndex(1);
@@ -20,7 +20,7 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
20
20
  await expect(appPicker).not.toBeDisplayedInViewport();
21
21
  await expect(triggerBtn).toBeFocused();
22
22
  });
23
- it('03: should open appPicker and have the third chip still focused', async () => {
23
+ it('03: should reopen appPicker with the selected app still marked as current', async () => {
24
24
  const openAppPickerBtn = await DSAppPickerCO.getOpenAppPicker();
25
25
  await openAppPickerBtn.click();
26
26
  const reportChip = await DSAppPickerCO.getChipByIndex(6);
@@ -0,0 +1,82 @@
1
+ import { Key } from 'webdriverio';
2
+ import DSAppPickerCO from '../DSAppPickerCO';
3
+
4
+ // Tests for the change introduced in PUI-18647 (GlobalHeader -> DSAppPicker contract passthrough).
5
+ // Widening the hand-off meant a consumer can finally supply a custom trigger, which exposed two
6
+ // different focus stories that now need pinning:
7
+ //
8
+ // - `TriggerComponent` (supported) receives `innerRef` AND the internal open handlers, so a keyboard
9
+ // open can run the selected-app focus logic and land on the selected chip.
10
+ // - `renderTrigger` (deprecated) receives only `ref`, so it cannot reach those handlers and falls
11
+ // back to focusing the panel on every path. Unchanged by design.
12
+ //
13
+ // The mouse path is the RE-BASELINE: a TriggerComponent picker opened with the mouse used to land on
14
+ // the FIRST app and now lands on the panel, matching the built-in trigger. Kept on the full browser
15
+ // matrix because pointer-driven focus is exactly where engines disagree.
16
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
17
+ describe('PUI-19014 - DSAppPicker:: custom trigger open focus destinations - Func', () => {
18
+ before('loading page', async () => {
19
+ const errorOnGo = await DSAppPickerCO.customTriggerFocusURL.go();
20
+ if (errorOnGo) throw errorOnGo;
21
+ });
22
+
23
+ it('01: should focus the panel when the supported trigger is opened with the mouse', async () => {
24
+ const trigger = await DSAppPickerCO.getSupportedCustomTrigger();
25
+ await trigger.waitForDisplayed();
26
+ await trigger.click();
27
+
28
+ const panel = await DSAppPickerCO.getAppPickerRoot();
29
+ await panel.waitForDisplayed();
30
+ await expect(panel).toBeFocused();
31
+ });
32
+
33
+ it('02: should focus the selected app when the supported trigger is opened with Enter', async () => {
34
+ // Escape closes the panel opened in 01 and returns focus to the trigger, which is also the
35
+ // starting state this case needs.
36
+ await browser.keys(Key.Escape);
37
+ const trigger = await DSAppPickerCO.getSupportedCustomTrigger();
38
+ await expect(trigger).toBeFocused();
39
+
40
+ await browser.keys(Key.Enter);
41
+ await (await DSAppPickerCO.getAppPickerRoot()).waitForDisplayed();
42
+
43
+ // 'Reports' is deliberately the third app, so "landed on the selected app" cannot be mistaken
44
+ // for "landed on the first app".
45
+ const selectedChip = await DSAppPickerCO.getChipByLabel('Reports');
46
+ await expect(selectedChip).toBeFocused();
47
+ await expect(await DSAppPickerCO.isSelected(selectedChip)).toBe(true);
48
+ });
49
+
50
+ it('03: should focus the panel when the deprecated trigger is opened with the mouse', async () => {
51
+ await browser.keys(Key.Escape);
52
+
53
+ const trigger = await DSAppPickerCO.getDeprecatedCustomTrigger();
54
+ await trigger.waitForDisplayed();
55
+ await trigger.click();
56
+
57
+ const panel = await DSAppPickerCO.getAppPickerRoot();
58
+ await panel.waitForDisplayed();
59
+ await expect(panel).toBeFocused();
60
+ });
61
+
62
+ it('04: should focus the panel when the deprecated trigger is opened with Enter', async () => {
63
+ // The panel 03 left open is controlled from the story and has no Escape handler, so it is
64
+ // dismissed by clicking its trigger again. Where a dismissal click leaves focus is NOT what
65
+ // this case is about and is not consistent across engines — clicking a <button> does not focus
66
+ // it on macOS, and the panel unmounting mid-click can blur. So the keyboard starting state is
67
+ // established explicitly instead of being inherited from the click.
68
+ const trigger = await DSAppPickerCO.getDeprecatedCustomTrigger();
69
+ await trigger.click();
70
+ await (await DSAppPickerCO.getAppPickerRoot()).waitForDisplayed({ reverse: true });
71
+
72
+ await browser.execute((el) => el.focus(), trigger);
73
+ await expect(trigger).toBeFocused();
74
+
75
+ await browser.keys(Key.Enter);
76
+
77
+ const panel = await DSAppPickerCO.getAppPickerRoot();
78
+ await panel.waitForDisplayed();
79
+ await expect(panel).toBeFocused();
80
+ });
81
+ });
82
+ }