dimsum-e2e-tests 3.70.0-next.3 → 3.70.0-next.30

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 (118) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/ds-accordion-native/DSAccordionNative.axe-core.func.spec.js +117 -0
  3. package/ds-accordion-native/DSAccordionNative.func.spec.js +178 -0
  4. package/ds-accordion-native/DSAccordionNative.visual.spec.js +131 -0
  5. package/ds-accordion-native/DSAccordionNativeCO.js +149 -0
  6. package/ds-accordion-native/aria-disabled/DSAccordionNative.aria-disabled.axe-core.func.spec.js +25 -0
  7. package/ds-accordion-native/aria-disabled/DSAccordionNative.aria-disabled.visual.spec.js +27 -0
  8. package/ds-accordion-native/role/DSAccordionNative.role-heading.func.spec.js +27 -0
  9. package/ds-accordion-native/scrollable-content/DSAccordionNative.scrollable-content.visual.spec.js +48 -0
  10. package/ds-accordion-native/slots/DSAccordionNative.slots.axe-core.func.spec.js +25 -0
  11. package/ds-accordion-native/slots/DSAccordionNative.slots.func.spec.js +73 -0
  12. package/ds-accordion-native/slots/DSAccordionNative.slots.visual.spec.js +18 -0
  13. package/ds-accordion-native/wrapLabel/DSAccordionNative.wrap-label.visual.spec.js +22 -0
  14. package/ds-apppicker/DSAppPickerCO.js +1 -1
  15. package/ds-autocomplete/DSAutocomplete.visual.spec.js +34 -0
  16. package/ds-autocomplete/DSAutocompleteCO.js +2 -0
  17. package/ds-chat/DSChat.axe-core.func.spec.js +2 -2
  18. package/ds-chat/DSChat.visual.spec.js +3 -3
  19. package/ds-chat/DSChatCO.js +17 -23
  20. package/ds-chat/bubbles/slots/DSChatBubble.slots.axe-core.func.spec.js +24 -0
  21. package/ds-chat/bubbles/slots/DSChatBubble.slots.func.spec.js +49 -0
  22. package/ds-chat/bubbles/slots/DSChatBubble.slots.visual.spec.js +25 -0
  23. package/ds-chat/card/slots/DSChatCard.slots.axe-core.func.spec.js +24 -0
  24. package/ds-chat/card/slots/DSChatCard.slots.func.spec.js +47 -0
  25. package/ds-chat/card/slots/DSChatCard.slots.visual.spec.js +18 -0
  26. package/ds-chat/card/truncated-text/DSChatCard.truncated-text.func.spec.js +32 -0
  27. package/ds-chat/card/truncated-text/DSChatCard.truncated-text.visual.spec.js +26 -0
  28. package/ds-chat/card/with-notification-badges/DSChatCard.with-notification-badges.axe-core.func.spec.js +23 -0
  29. package/ds-chat/card/with-notification-badges/DSChatCard.with-notification-badges.visual.spec.js +17 -0
  30. package/ds-chat/components/BubbleCO.js +46 -3
  31. package/ds-chat/components/CardCO.js +77 -0
  32. package/ds-chat/components/ComposerCO.js +6 -6
  33. package/ds-chat/components/FloatingButtonCO.js +2 -2
  34. package/ds-chat/components/HeaderCO.js +2 -2
  35. package/ds-chat/components/TileCO.js +82 -0
  36. package/ds-chat/components/index.js +3 -2
  37. package/ds-chat/loadmore/DSChat-loadmore.func.spec.js +1 -1
  38. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.axe-core.func.spec.js +2 -2
  39. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.func.spec.js +1 -1
  40. package/{ds-chat-tile → ds-chat/tile}/DSChat-tile.visual.spec.js +2 -2
  41. package/{ds-chat-tile → ds-chat/tile}/aria-disabled/DSChat-tile.aria-disabled.axe-core.func.spec.js +2 -2
  42. package/{ds-chat-tile → ds-chat/tile}/aria-disabled/DSChat-tile.aria-disabled.visual.spec.js +1 -1
  43. package/ds-chat/tile/slots/DSChatTile.slots.func.spec.js +53 -0
  44. package/ds-chat/tile/slots/DSChatTile.slots.visual.spec.js +18 -0
  45. package/ds-controlled-form/ds-combobox/DSComboboxCO.js +2 -2
  46. package/ds-controlled-form/ds-controlled-checkbox/DSControlledCheckboxCO.js +1 -1
  47. package/ds-controlled-form/ds-controlled-inputgroup/DSControlledInputGroupCO.js +1 -1
  48. package/ds-data-table-async/DSDataTableCO.js +10 -12
  49. package/ds-data-table-async/basic/DSDataTable.basic.visual.spec.js +1 -1
  50. package/ds-data-table-async/components/FiltersCO.js +1 -1
  51. package/ds-data-table-async/components/HeaderCO.js +22 -10
  52. package/ds-dialog/DSDialog.visual.spec.js +16 -31
  53. package/ds-dialog/DSDialogCO.js +58 -0
  54. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-critical.axe-core.func.spec.js +27 -0
  55. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-critical.func.spec.js +56 -0
  56. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-critical.visual.spec.js +20 -0
  57. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-dismissible.axe-core.func.spec.js +25 -0
  58. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-dismissible.func.spec.js +52 -0
  59. package/ds-dialog/alert-dialog/DSDialog.alert-dialog-dismissible.visual.spec.js +20 -0
  60. package/ds-dialog/axe-core/DSDialog.accessible-form.axe-core.func.spec.js +25 -0
  61. package/ds-dialog/axe-core/DSDialog.basic.axe-core.func.spec.js +25 -0
  62. package/ds-dialog/axe-core/DSDialog.centered.axe-core.func.spec.js +25 -0
  63. package/ds-dialog/axe-core/DSDialog.decision.axe-core.func.spec.js +57 -0
  64. package/ds-dialog/axe-core/DSDialog.long-body.axe-core.func.spec.js +25 -0
  65. package/ds-dialog/axe-core/DSDialog.warning.axe-core.func.spec.js +24 -0
  66. package/ds-dialog/axe-core/DSDialog.wizard.axe-core.func.spec.js +28 -0
  67. package/ds-dialog/click-outside/DSDialog.click-outside.func.spec.js +31 -0
  68. package/ds-dialog/esc-close/DSDialog.esc-close.func.spec.js +31 -0
  69. package/ds-dialog/flexible-heading-level/DSDialog.flexible-heading-level.axe-core.func.spec.js +46 -0
  70. package/ds-dialog/flexible-heading-level/DSDialog.flexible-heading-level.func.spec.js +50 -0
  71. package/ds-dialog/form-dialog-datepicker/DSDialog.form-datepicker.axe-core.func.spec.js +25 -0
  72. package/ds-dialog/form-dialog-datepicker/DSDialog.form-datepicker.visual.spec.js +37 -0
  73. package/ds-dialog/single-button-footer/DSDialog.single-button-footer.axe-core.func.spec.js +25 -0
  74. package/ds-dialog/single-button-footer/DSDialog.single-button-footer.visual.spec.js +20 -0
  75. package/ds-dialog/size-variants/DSDialog.size-variants.visual.spec.js +116 -0
  76. package/ds-floating-context/DSFloatingContextCO.js +10 -0
  77. package/ds-floating-context/placement/DSFloatingContext.placement.visual.spec.js +48 -0
  78. package/ds-form-combobox-multi/DSComboboxMultiCO.js +8 -2
  79. package/ds-form-combobox-multi/aria-busy-loading/DSComboboxMulti.aria-busy-loading.axe-core.func.spec.js +55 -0
  80. package/ds-form-combobox-multi/aria-busy-loading/DSComboboxMulti.aria-busy-loading.func.spec.js +57 -0
  81. package/ds-form-combobox-multi/aria-disabled/DSComboboxMulti.aria-disabled.visual.spec.js +15 -0
  82. package/ds-form-combobox-multi/disabled/DSComboboxMulti.disabled.axe-core.func.spec.js +24 -0
  83. package/ds-form-combobox-multi/inline/DSComboboxMulti.inline.visual.spec.js +21 -0
  84. package/ds-form-combobox-single/DSComboboxSingleCO.js +8 -2
  85. package/ds-form-combobox-single/aria-busy-loading/DSComboboxSingle.aria-busy-loading.axe-core.func.spec.js +49 -0
  86. package/ds-form-combobox-single/aria-busy-loading/DSComboboxSingle.aria-busy-loading.func.spec.js +54 -0
  87. package/ds-form-combobox-single/aria-disabled/DSComboboxSingle.aria-disabled.visual.spec.js +18 -0
  88. package/ds-form-combobox-single/disabled/DSComboboxSingle.disabled.axe-core.func.spec.js +24 -0
  89. package/ds-form-combobox-single/inline/DSComboboxSingle.inline.visual.spec.js +23 -0
  90. package/ds-form-native-select/NativeSelect.axe-core.func.spec.js +39 -0
  91. package/ds-form-native-select/NativeSelect.visual.spec.js +33 -0
  92. package/ds-form-native-select/NativeSelectCO.js +6 -0
  93. package/ds-form-native-select/option-selection/NativeSelect.option-selection.func.spec.js +25 -0
  94. package/ds-global-header/GlobalHeader.axe-core.func.spec.js +30 -0
  95. package/ds-global-header/GlobalHeader.visual.spec.js +31 -0
  96. package/ds-leftnavigation/LeftNavigationCO.js +2 -2
  97. package/ds-menu-button/DSMenuButtonCO.js +23 -0
  98. package/ds-menu-button/slots/DSMenuButton.slots.func.spec.js +40 -0
  99. package/ds-menu-button/slots/DSMenuButton.slots.visual.spec.js +26 -0
  100. package/ds-modal-slide/ModalSlideCO.js +39 -0
  101. package/ds-modal-slide/custom-header/ModalSlide.customHeader.focusRing.visual.spec.js +2 -1
  102. package/ds-modal-slide/slots/ModalSlide.slots.func.spec.js +74 -0
  103. package/ds-modal-slide/slots/ModalSlide.slots.visual.spec.js +27 -0
  104. package/ds-page-layout/PageLayoutCO.js +4 -4
  105. package/ds-progress-indicator/DSProgressIndicator.axe-core.func.spec.js +2 -0
  106. package/ds-progress-indicator/DSProgressIndicatorCO.js +1 -1
  107. package/ds-tab-button/DSTabButton.func.spec.js +1 -1
  108. package/ds-tabs/DSTabs.visual.spec.js +1 -2
  109. package/ds-tabs/DSTabsCO.js +2 -2
  110. package/ds-tabs/with-carousel/DSTabs.with-carousel.func.spec.js +22 -7
  111. package/ds-tabs/with-carousel/DSTabs.with-carousel.visual.spec.js +9 -9
  112. package/ds-tooltip-v3/DSTooltipV3CO.js +6 -0
  113. package/ds-tooltip-v3/aria-tooltip-pattern/DSTooltipV3.aria-tooltip-pattern.axe-core.func.spec.js +23 -0
  114. package/ds-tooltip-v3/aria-tooltip-pattern/DSTooltipV3.aria-tooltip-pattern.func.spec.js +29 -0
  115. package/ds-treeview/DSTreeViewCO.js +2 -2
  116. package/package.json +150 -153
  117. package/paths.js +8 -1
  118. package/ds-chat-tile/TileCO.js +0 -35
@@ -54,4 +54,43 @@ if (
54
54
  expect(result.length).toBe(0);
55
55
  });
56
56
  });
57
+
58
+ describe('PUI-16464 - NativeSelect: ApplyAriaDisabled -AxeCore', () => {
59
+ before(async () => {
60
+ const errorOnGo = await NativeSelect.applyAriaDisabledURL.go();
61
+ if (errorOnGo) throw errorOnGo;
62
+ });
63
+ it('01: should have applyAriaDisabled native select and pass axe-core scan', async () => {
64
+ const nativeSelect = await NativeSelect.getRootByIndex(0);
65
+ await nativeSelect.waitForDisplayed();
66
+ const result = await axeCoreCheck();
67
+ expect(result.length).toBe(0);
68
+ });
69
+ });
70
+
71
+ describe('PUI-16464 - NativeSelect: ReadOnly -AxeCore', () => {
72
+ before(async () => {
73
+ const errorOnGo = await NativeSelect.readOnlyURL.go();
74
+ if (errorOnGo) throw errorOnGo;
75
+ });
76
+ it('01: should have readOnly native select and pass axe-core scan', async () => {
77
+ const nativeSelect = await NativeSelect.getRootByIndex(0);
78
+ await nativeSelect.waitForDisplayed();
79
+ const result = await axeCoreCheck();
80
+ expect(result.length).toBe(0);
81
+ });
82
+ });
83
+
84
+ describe('PUI-16464 - NativeSelect: ApplyAriaDisabled + hasError -AxeCore', () => {
85
+ before(async () => {
86
+ const errorOnGo = await NativeSelect.applyAriaDisabledWithErrorURL.go();
87
+ if (errorOnGo) throw errorOnGo;
88
+ });
89
+ it('01: should have applyAriaDisabled + hasError native select and pass axe-core scan', async () => {
90
+ const nativeSelect = await NativeSelect.getRootByIndex(0);
91
+ await nativeSelect.waitForDisplayed();
92
+ const result = await axeCoreCheck();
93
+ expect(result.length).toBe(0);
94
+ });
95
+ });
57
96
  }
@@ -0,0 +1,33 @@
1
+ import NativeSelect from './NativeSelectCO';
2
+
3
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
4
+ describe('PUI-18537 - NativeSelect:: basic state -Visual', () => {
5
+ before('loading page', async () => {
6
+ const errorOnGo = await NativeSelect.controlledURL.go();
7
+ if (errorOnGo) throw errorOnGo;
8
+ });
9
+
10
+ it('01: should render the basic controlled native select', async () => {
11
+ const root = await NativeSelect.getRootByIndex(0);
12
+ await root.waitForDisplayed();
13
+ const snapshot = await browser.percyCheckScreenshot(NativeSelect.snapshotPath('basic'));
14
+ await expect(snapshot).toEqual(0);
15
+ });
16
+ });
17
+
18
+ // Coverage for the fix introduced in PUI-14617
19
+ // (disabled-state colors aligned with Combobox disabled-state colors to meet WCAG 1.4.3).
20
+ describe('PUI-18538 - NativeSelect:: disabled state -Visual', () => {
21
+ before('loading page', async () => {
22
+ const errorOnGo = await NativeSelect.disabledURL.go();
23
+ if (errorOnGo) throw errorOnGo;
24
+ });
25
+
26
+ it('01: should render the disabled native select', async () => {
27
+ const root = await NativeSelect.getRootByIndex(0);
28
+ await root.waitForDisplayed();
29
+ const snapshot = await browser.percyCheckScreenshot(NativeSelect.snapshotPath('disabled'));
30
+ await expect(snapshot).toEqual(0);
31
+ });
32
+ });
33
+ }
@@ -11,6 +11,12 @@ export default class NativeSelect extends PageObject {
11
11
 
12
12
  static disabledURL = new Urlbuilder(PATH_E2E_NATIVE_SELECT, 'disabled-test');
13
13
 
14
+ static applyAriaDisabledURL = new Urlbuilder(PATH_E2E_NATIVE_SELECT, 'apply-aria-disabled-test');
15
+
16
+ static readOnlyURL = new Urlbuilder(PATH_E2E_NATIVE_SELECT, 'read-only-test');
17
+
18
+ static applyAriaDisabledWithErrorURL = new Urlbuilder(PATH_E2E_NATIVE_SELECT, 'apply-aria-disabled-with-error-test');
19
+
14
20
  // Selectors
15
21
  static async getInputSlotByIndex(index = 0) {
16
22
  return $$(`[data-dimsum-slot="dsNativeselectInput"]`)[index];
@@ -0,0 +1,25 @@
1
+ import NativeSelect from '../NativeSelectCO';
2
+
3
+ // Tests for the option selection behavior of the native select introduced in PUI-14617.
4
+ // Selecting an option must update the <select> value (options use value={index}).
5
+ // Uses the WebDriver native select command (selectByIndex) so the native popup is opened and an
6
+ // option committed the same way in every browser — simulated keystrokes on the OS-drawn popup are
7
+ // not reachable by WebDriver on macOS/Safari, which is why a keystroke-based assertion is not portable.
8
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
9
+ describe('PUI-18563 - NativeSelect:: Option selection updates value -Func', () => {
10
+ before(async () => {
11
+ const errorOnGo = await NativeSelect.controlledURL.go();
12
+ if (errorOnGo) throw errorOnGo;
13
+ });
14
+
15
+ it('01: should update the value when selecting an option from the popup', async () => {
16
+ const nativeSelect = await NativeSelect.getRootByIndex(0);
17
+ await nativeSelect.waitForDisplayed();
18
+
19
+ const input = await NativeSelect.getInputSlotByIndex(0);
20
+ await input.selectByIndex(2);
21
+
22
+ await expect(input).toHaveValue('2');
23
+ });
24
+ });
25
+ }
@@ -90,6 +90,36 @@ if (
90
90
  });
91
91
  });
92
92
 
93
+ // Skipped due to defect PUI-17970
94
+ describe.skip('PUI-18379 - GlobalHeader: with search toggle -AxeCore', () => {
95
+ before(async () => {
96
+ const errorOnGo = await GlobalHeaderCO.withSearchToggleURL.go();
97
+ if (errorOnGo) throw errorOnGo;
98
+ });
99
+ it('01: should have global header with search toggle and pass axe-core scan', async () => {
100
+ const globalHeader = await GlobalHeaderCO.getGlobalHeader();
101
+ await globalHeader.waitForDisplayed();
102
+ const toggleSearch = await GlobalHeaderCO.getGHToolbarItem(0);
103
+ await expect(toggleSearch).toHaveAttribute('aria-expanded', 'false');
104
+ await expect(toggleSearch).toHaveAttribute('aria-controls');
105
+ const result = await axeCoreCheck();
106
+ expect(result.length).toBe(0);
107
+ });
108
+ it('02: should have global header with search toggle expanded and pass axe-core scan', async () => {
109
+ const toggleSearch = await GlobalHeaderCO.getGHToolbarItem(0);
110
+ await toggleSearch.click();
111
+ await expect(toggleSearch).toHaveAttribute('aria-expanded', 'true');
112
+ await expect(toggleSearch).toHaveAttribute('aria-controls', /^ds-global-header/);
113
+ const result = await axeCoreCheck();
114
+ expect(result.length).toBe(0);
115
+ });
116
+ it('03: should have global header with populated search toggle and pass axe-core scan', async () => {
117
+ await type('Labor');
118
+ const result = await axeCoreCheck();
119
+ expect(result.length).toBe(0);
120
+ });
121
+ });
122
+
93
123
  // Skipped due to defect PUI-17970
94
124
  describe.skip('PUI-16270 - GlobalHeader: Controled with Iframe -AxeCore', () => {
95
125
  before(async () => {
@@ -164,4 +164,35 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
164
164
  await expect(snapshot).toEqual(0);
165
165
  });
166
166
  });
167
+
168
+ describe('PUI-18378 - GlobalHeader: with SearchToggle -Visual', () => {
169
+ before(async () => {
170
+ const errorOnGo = await GlobalHeader.withSearchToggleURL.go();
171
+ if (errorOnGo) throw errorOnGo;
172
+ });
173
+ it('01: should display global header with expanded search toggle', async () => {
174
+ await browser.eyesOpen();
175
+ const searchToggleTrigger = await GlobalHeader.getGHToolbarItem(0);
176
+ await searchToggleTrigger.click();
177
+ const snapshot = await browser.eyesCheckSnapshot(GlobalHeader.snapshotPath('global-with-searchbox-open'));
178
+ await expect(snapshot).toEqual(0);
179
+ });
180
+ it('02: should display global header with populated search toggle', async () => {
181
+ await browser.eyesOpen();
182
+ await browser.keys(Key.Tab);
183
+ await browser.keys('Labor');
184
+ const snapshot = await browser.eyesCheckSnapshot(GlobalHeader.snapshotPath('global-with-searchbox-populated'));
185
+ await expect(snapshot).toEqual(0);
186
+ });
187
+ it('03: should display global header with focused spinbutton and highlighted result', async () => {
188
+ await browser.eyesOpen();
189
+ await browser.keys(Key.Tab);
190
+ await browser.keys(Key.Tab);
191
+ await browser.keys(Key.ArrowUp);
192
+ const globalHeader = await GlobalHeader.getGlobalHeader();
193
+ await globalHeader.waitForDisplayed();
194
+ const snapshot = await browser.eyesCheckSnapshot(GlobalHeader.snapshotPath('global-with-searchbox-highlight'));
195
+ await expect(snapshot).toEqual(0);
196
+ });
197
+ });
167
198
  }
@@ -71,11 +71,11 @@ export default class LeftNavCO extends PageObject {
71
71
  }
72
72
 
73
73
  static async getTruncatedText(index) {
74
- return $$('[data-testid="DS-SimpleTruncateText"]')[index];
74
+ return $$('[data-testid="leftnav-list-item-label"]')[index];
75
75
  }
76
76
 
77
77
  static async getTooltip() {
78
- return $('[data-testid="popover-container"]');
78
+ return $('[data-testid="ds-floating-wrapper-root"]');
79
79
  }
80
80
 
81
81
  static async getSubItemBtn() {
@@ -21,6 +21,8 @@ export default class DSMenuButtonCO extends PageObject {
21
21
 
22
22
  static skeletonMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'skeleton-menu-item-test');
23
23
 
24
+ static slotsTest = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'slots-test');
25
+
24
26
  // UseCases (E2E simplified versions)
25
27
  static cardExample = new Urlbuilder(PATH_MENU_BUTTON_USECASES, 'card-example-test');
26
28
 
@@ -85,6 +87,27 @@ export default class DSMenuButtonCO extends PageObject {
85
87
  return $(`${item} div span`);
86
88
  }
87
89
 
90
+ // Slots test selectors (by data-dimsum-slot)
91
+ static async getSlotsOpinionatedButtonRoot() {
92
+ return $('[data-dimsum-parent-slot="dsOpinionatedbuttonRoot"');
93
+ }
94
+
95
+ static async getSlotsFloatingWrapper() {
96
+ return $('[data-dimsum-parent-slot="dsFlyoutmenuFloatingWrapper"');
97
+ }
98
+
99
+ static async getSlotsFlyoutMenuRoot() {
100
+ return $('[data-dimsum-slot="dsFlyoutmenuRoot"]');
101
+ }
102
+
103
+ static async getSlotsListWrapper() {
104
+ return $('[data-dimsum-slot="dsFlyoutmenuListWrapper"]');
105
+ }
106
+
107
+ static async getSlotsMenuItemWrappers(index = 0) {
108
+ return $$('[data-dimsum-slot="dsMenuitemMenuItemWrapper"]')[index];
109
+ }
110
+
88
111
  // Snapshots
89
112
  static snapshotPath(example = 'basic') {
90
113
  return PageObject.getSnapshotPathBuilder('DSMenuItems', example, 'ds-menu-items');
@@ -0,0 +1,40 @@
1
+ import DSMenuButtonCO from '../DSMenuButtonCO';
2
+
3
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
4
+ describe('PUI-18356 - DSMenuButton:: Slots - Func', () => {
5
+ before('loading page', async () => {
6
+ const errorOnGo = await DSMenuButtonCO.slotsTest.go();
7
+ if (errorOnGo) throw errorOnGo;
8
+ });
9
+
10
+ it('01: should have custom aria-label to each slot', async () => {
11
+ const triggerBtn = await DSMenuButtonCO.getSlotsOpinionatedButtonRoot();
12
+ await expect(triggerBtn).toHaveAttribute('aria-label', 'im dsOpinionatedbuttonRoot aria');
13
+ await triggerBtn.click();
14
+
15
+ const flyoutRoot = await DSMenuButtonCO.getSlotsFlyoutMenuRoot();
16
+ await flyoutRoot.waitForDisplayed();
17
+ const listWrapper = await DSMenuButtonCO.getSlotsListWrapper();
18
+ const floatingWrapper = await DSMenuButtonCO.getSlotsFloatingWrapper();
19
+ const menuItem = await DSMenuButtonCO.getSlotsMenuItemWrappers();
20
+ await expect(listWrapper).toHaveAttribute('aria-label', 'im dsFlyoutmenuListWrapper aria');
21
+ await expect(flyoutRoot).toHaveAttribute('aria-label', 'im dsFlyoutmenuRoot aria');
22
+ await expect(floatingWrapper).toHaveAttribute('aria-label', 'im dsFlyoutmenuFloatingWrapper aria');
23
+ await expect(menuItem).toHaveAttribute('aria-label', 'im dsMenuitemMenuItemWrapper aria');
24
+ });
25
+
26
+ it('02: should apply custom data-testid to each slot', async () => {
27
+ const triggerBtn = await DSMenuButtonCO.getSlotsOpinionatedButtonRoot();
28
+ const flyoutRoot = await DSMenuButtonCO.getSlotsFlyoutMenuRoot();
29
+ const listWrapper = await DSMenuButtonCO.getSlotsListWrapper();
30
+ const floatingWrapper = await DSMenuButtonCO.getSlotsFloatingWrapper();
31
+ const menuItem = await DSMenuButtonCO.getSlotsMenuItemWrappers();
32
+
33
+ await expect(triggerBtn).toHaveAttribute('data-testid', 'im dsOpinionatedbuttonRoot data');
34
+ await expect(flyoutRoot).toHaveAttribute('data-testid', 'im dsFlyoutmenuRoot data');
35
+ await expect(listWrapper).toHaveAttribute('data-testid', 'im dsFlyoutmenuListWrapper data');
36
+ await expect(floatingWrapper).toHaveAttribute('data-testid', 'im dsFlyoutmenuFloatingWrapper data');
37
+ await expect(menuItem).toHaveAttribute('data-testid', 'im dsMenuitemMenuItemWrapper data');
38
+ });
39
+ });
40
+ }
@@ -0,0 +1,26 @@
1
+ import DSMenuButtonCO from '../DSMenuButtonCO';
2
+
3
+ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
4
+ describe('PUI-18357 - DSMenuButton:: Slots - Visual', () => {
5
+ before('loading page', async () => {
6
+ const errorOnGo = await DSMenuButtonCO.slotsTest.go();
7
+ if (errorOnGo) throw errorOnGo;
8
+ });
9
+
10
+ it('01: should display slots story in dark theme default state correctly', async () => {
11
+ const triggerBtn = await DSMenuButtonCO.getSlotsOpinionatedButtonRoot();
12
+ await triggerBtn.waitForDisplayed();
13
+ const snapshot = await browser.percyCheckScreenshot(DSMenuButtonCO.snapshotPath('slots-default'));
14
+ await expect(snapshot).toEqual(0);
15
+ });
16
+
17
+ it('02: should display slots story with menu open in dark theme correctly', async () => {
18
+ const triggerBtn = await DSMenuButtonCO.getSlotsOpinionatedButtonRoot();
19
+ await triggerBtn.click();
20
+ const flyoutRoot = await DSMenuButtonCO.getSlotsFlyoutMenuRoot();
21
+ await flyoutRoot.waitForDisplayed();
22
+ const snapshot = await browser.percyCheckScreenshot(DSMenuButtonCO.snapshotPath('slots-open'));
23
+ await expect(snapshot).toEqual(0);
24
+ });
25
+ });
26
+ }
@@ -31,6 +31,8 @@ export default class ModalSlideCO extends PageObject {
31
31
 
32
32
  static applyAriaDisabledFooterURL = new Urlbuilder(PATH_E2E_MODALSLIDE, 'apply-aria-disabled-footer-test');
33
33
 
34
+ static slotsTest = new Urlbuilder(PATH_E2E_MODALSLIDE, 'slots-test');
35
+
34
36
  static async getModalSlide() {
35
37
  return $('[data-testid="ds-modal-slide"]');
36
38
  }
@@ -95,6 +97,43 @@ export default class ModalSlideCO extends PageObject {
95
97
  await browser.pause(500); // pause to allow animation to finish
96
98
  }
97
99
 
100
+ // Slots
101
+ static async getSlotActualContent() {
102
+ return $('[data-dimsum-slot="dsModalslideActualContent"]');
103
+ }
104
+
105
+ static async getSlotContent() {
106
+ return $('[data-dimsum-slot="dsModalslideContent"]');
107
+ }
108
+
109
+ static async getSlotContentWrapper() {
110
+ return $('[data-dimsum-slot="dsModalslideContentWrapper"]');
111
+ }
112
+
113
+ static async getSlotFooterSeparator() {
114
+ return $('[data-dimsum-slot="dsModalslideFooterSeparator"]');
115
+ }
116
+
117
+ static async getSlotGridContent() {
118
+ return $('[data-dimsum-slot="dsModalslideGridContent"]');
119
+ }
120
+
121
+ static async getSlotHeaderSeparator() {
122
+ return $('[data-dimsum-slot="dsModalslideHeaderSeparator"]');
123
+ }
124
+
125
+ static async getSlotOverlay() {
126
+ return $('[data-dimsum-slot="dsModalslideOverlay"]');
127
+ }
128
+
129
+ static async getSlotRoot() {
130
+ return $('[data-dimsum-slot="dsModalslideRoot"]');
131
+ }
132
+
133
+ static async getSlotHeader() {
134
+ return $('[data-dimsum-parent-slot="dsModalslideTitle"]');
135
+ }
136
+
98
137
  // Snapshots
99
138
  static snapshotPath(example = 'basic') {
100
139
  return PageObject.getSnapshotPathBuilder('ModalSlide', example, 'ds-modal-slide');
@@ -10,7 +10,8 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
10
10
  });
11
11
 
12
12
  it('01: should show consistent focus ring on modal body (5th tab stop)', async () => {
13
- await ModalSlideCO.openModalSlide();
13
+ const trigger = await ModalSlideCO.getOpenModalSlideBtn();
14
+ await trigger.click();
14
15
  // Tab through CustomHeader: backarrow(1) -> breadcrumb items(2,3,4) -> body(5)
15
16
  await browser.keys(Key.Tab);
16
17
  await browser.keys(Key.Tab);
@@ -0,0 +1,74 @@
1
+ /* eslint-disable max-lines */
2
+ import { Key } from 'webdriverio';
3
+ import ModalSlideCO from '../ModalSlideCO';
4
+
5
+ if (
6
+ (!browser.capabilities['ice:options'].isPhone &&
7
+ !browser.capabilities['ice:options'].isTablet &&
8
+ browser.capabilities.browserName === 'chrome') ||
9
+ browser.capabilities.browserName === 'Chrome'
10
+ ) {
11
+ describe('PUI-18428 - SquareIndicator: Slots - Func Test', () => {
12
+ before('loading page', async () => {
13
+ const errorOnGo = await ModalSlideCO.slotsTest.go();
14
+ if (errorOnGo) throw errorOnGo;
15
+ });
16
+ it('01: each SquareIndicator slot to have custom aria-* attribute', async () => {
17
+ await browser.keys(Key.Tab);
18
+ await browser.keys(Key.Tab);
19
+ await browser.keys(Key.Return);
20
+ const actualContent = await ModalSlideCO.getSlotActualContent();
21
+ const content = await ModalSlideCO.getSlotContent();
22
+ const contentWrapper = await ModalSlideCO.getSlotContentWrapper();
23
+ const footerSeparator = await ModalSlideCO.getSlotFooterSeparator();
24
+ const gridContent = await ModalSlideCO.getSlotGridContent();
25
+ const headerSeparator = await ModalSlideCO.getSlotHeaderSeparator();
26
+ const overlay = await ModalSlideCO.getSlotOverlay();
27
+ const root = await ModalSlideCO.getSlotRoot();
28
+ await expect(actualContent).toHaveAttribute('aria-label', 'actual content aria');
29
+ await expect(content).toHaveAttribute('aria-label', 'content aria');
30
+ await expect(contentWrapper).toHaveAttribute('aria-label', 'content wrapper aria');
31
+ await expect(footerSeparator).toHaveAttribute('aria-label', 'footer separator aria');
32
+ await expect(gridContent).toHaveAttribute('aria-label', 'grid content aria');
33
+ await expect(headerSeparator).toHaveAttribute('aria-label', 'header separator aria');
34
+ await expect(overlay).toHaveAttribute('aria-label', 'overlay aria');
35
+ await expect(root).toHaveAttribute('aria-label', 'root aria');
36
+ });
37
+ it('02: each SquareIndicator slot to have custom data-* attribute', async () => {
38
+ const actualContent = await ModalSlideCO.getSlotActualContent();
39
+ const content = await ModalSlideCO.getSlotContent();
40
+ const contentWrapper = await ModalSlideCO.getSlotContentWrapper();
41
+ const footerSeparator = await ModalSlideCO.getSlotFooterSeparator();
42
+ const gridContent = await ModalSlideCO.getSlotGridContent();
43
+ const headerSeparator = await ModalSlideCO.getSlotHeaderSeparator();
44
+ const overlay = await ModalSlideCO.getSlotOverlay();
45
+ const root = await ModalSlideCO.getSlotRoot();
46
+ await expect(actualContent).toHaveAttribute('data-testid', 'actual content data');
47
+ await expect(content).toHaveAttribute('data-testid', 'content data');
48
+ await expect(contentWrapper).toHaveAttribute('data-testid', 'content wrapper data');
49
+ await expect(footerSeparator).toHaveAttribute('data-testid', 'footer separator data');
50
+ await expect(gridContent).toHaveAttribute('data-testid', 'grid content data');
51
+ await expect(headerSeparator).toHaveAttribute('data-testid', 'header separator data');
52
+ await expect(overlay).toHaveAttribute('data-testid', 'overlay data');
53
+ await expect(root).toHaveAttribute('data-testid', 'root data');
54
+ });
55
+ it('03: each ModalSlide slot to have custom lang attribute', async () => {
56
+ const actualContent = await ModalSlideCO.getSlotActualContent();
57
+ const content = await ModalSlideCO.getSlotContent();
58
+ const contentWrapper = await ModalSlideCO.getSlotContentWrapper();
59
+ const footerSeparator = await ModalSlideCO.getSlotFooterSeparator();
60
+ const gridContent = await ModalSlideCO.getSlotGridContent();
61
+ const headerSeparator = await ModalSlideCO.getSlotHeaderSeparator();
62
+ const overlay = await ModalSlideCO.getSlotOverlay();
63
+ const root = await ModalSlideCO.getSlotRoot();
64
+ await expect(actualContent).toHaveAttribute('lang', 'en');
65
+ await expect(content).toHaveAttribute('lang', 'es');
66
+ await expect(contentWrapper).toHaveAttribute('lang', 'fr');
67
+ await expect(footerSeparator).toHaveAttribute('lang', 'de');
68
+ await expect(gridContent).toHaveAttribute('lang', 'it');
69
+ await expect(headerSeparator).toHaveAttribute('lang', 'pt');
70
+ await expect(overlay).toHaveAttribute('lang', 'ja');
71
+ await expect(root).toHaveAttribute('lang', 'zh');
72
+ });
73
+ });
74
+ }
@@ -0,0 +1,27 @@
1
+ /* eslint-disable max-lines */
2
+ import { Key } from 'webdriverio';
3
+ import ModalSlideCO from '../ModalSlideCO';
4
+
5
+ if (
6
+ (!browser.capabilities['ice:options'].isPhone &&
7
+ !browser.capabilities['ice:options'].isTablet &&
8
+ browser.capabilities.browserName === 'chrome') ||
9
+ browser.capabilities.browserName === 'Chrome'
10
+ ) {
11
+ describe('PUI-18429 - ModalSlide: Slots Test - Visual', () => {
12
+ before('loading page', async () => {
13
+ const errorOnGo = await ModalSlideCO.slotsTest.go();
14
+ if (errorOnGo) throw errorOnGo;
15
+ });
16
+ it('01: should display ModalSlide with customized slots', async () => {
17
+ await browser.eyesOpen();
18
+ await browser.keys(Key.Tab);
19
+ await browser.keys(Key.Tab);
20
+ await browser.keys(Key.Return);
21
+ const root = await ModalSlideCO.getSlotRoot();
22
+ await root.waitForDisplayed();
23
+ const snapshot = await browser.eyesCheckSnapshot(ModalSlideCO.snapshotPath('modal-slide-slots'));
24
+ await expect(snapshot).toEqual(0);
25
+ });
26
+ });
27
+ }
@@ -1,12 +1,12 @@
1
- import { PATH_PAGE_LAYOUT_TEMPLATE } from '../paths';
1
+ import { PATH_E2E_PAGE_LAYOUT } from '../paths';
2
2
  import { PageObject, Urlbuilder } from '../helpers';
3
3
 
4
4
  export default class PageLayoutCO extends PageObject {
5
- static basicURL = new Urlbuilder(PATH_PAGE_LAYOUT_TEMPLATE, 'basic');
5
+ static basicURL = new Urlbuilder(PATH_E2E_PAGE_LAYOUT, 'basic-test');
6
6
 
7
- static complexURL = new Urlbuilder(PATH_PAGE_LAYOUT_TEMPLATE, 'complex-page');
7
+ static complexURL = new Urlbuilder(PATH_E2E_PAGE_LAYOUT, 'complex-page-test');
8
8
 
9
- static integratedURL = new Urlbuilder(PATH_PAGE_LAYOUT_TEMPLATE, 'integrated-example');
9
+ static integratedURL = new Urlbuilder(PATH_E2E_PAGE_LAYOUT, 'integrated-example-test');
10
10
 
11
11
  // Snapshots
12
12
  static snapshotPath(example = 'basic') {
@@ -1,3 +1,4 @@
1
+ /* eslint-disable wdio/no-pause */
1
2
  import DSProgressIndicatorCO from './DSProgressIndicatorCO';
2
3
  import { axeCoreCheck } from '../helpers';
3
4
 
@@ -14,6 +15,7 @@ if (
14
15
  });
15
16
  it('01: should display basic progress indicator and pass axe-core', async () => {
16
17
  await (await DSProgressIndicatorCO.getUploadLabel()).waitForDisplayed();
18
+ await browser.pause(500);
17
19
  const result = await axeCoreCheck();
18
20
  expect(result.length).toBe(0);
19
21
  });
@@ -12,7 +12,7 @@ export default class DSProgressIndicatorCO extends PageObject {
12
12
  }
13
13
 
14
14
  static async getUploadLabel() {
15
- return $('//div[contains(text(), "upload")]');
15
+ return $('//span[contains(text(), "upload")]');
16
16
  }
17
17
 
18
18
  // Snapshots
@@ -12,7 +12,7 @@ import DSTabButtonCO from './DSTabButtonCO';
12
12
  });
13
13
  }
14
14
  */
15
- describe('PUI-XXXX - TabButton:: example test - data-testid exists', () => {
15
+ describe.skip('PUI-XXXX - TabButton:: example test - data-testid exists', () => {
16
16
  before('loading page', async () => {
17
17
  const errorOnGo = await DSTabButtonCO.basic.go();
18
18
  if (errorOnGo) throw errorOnGo;
@@ -95,8 +95,7 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
95
95
  const lastTab = await DSTabsCO.getTab(4);
96
96
  await lastTab.scrollIntoView();
97
97
  await browser.pause(1000);
98
- await lastTab.waitForClickable({ timeout: 5000 });
99
- await lastTab.click();
98
+ await browser.execute((el) => el.click(), lastTab);
100
99
  const snapshot = await browser.checkSnapshot(DSTabsCO.snapshotPath('tab-grid-moved2'));
101
100
  await expect(snapshot).toEqual(0);
102
101
  });
@@ -112,11 +112,11 @@ export default class DSTabsCO extends PageObject {
112
112
 
113
113
  static getTabListSlotByIndex = async (index = 0) => $$('[data-dimsum-slot="dsTabsTabList"]')[index];
114
114
 
115
- static getTabButtonSlotByIndex = async (index = 0) => $$('[data-dimsum-slot="dsTabsTabButton"]')[index];
115
+ static getTabButtonSlotByIndex = async (index = 0) => $$('[data-dimsum-parent-slot="dsTabsTabButton"]')[index];
116
116
 
117
117
  static getTabPanelSlotByIndex = async (index = 0) => $$('[data-dimsum-slot="dsTabsTabPanel"]')[index];
118
118
 
119
119
  static getSubtabsListSlotByIndex = async (index = 0) => $$('[data-dimsum-slot="dsTabsSubtabsList"]')[index];
120
120
 
121
- static getSubtabButtonSlotByIndex = async (index = 0) => $$('[data-dimsum-slot="dsTabsSubtabButton"]')[index];
121
+ static getSubtabButtonSlotByIndex = async (index = 0) => $$('[data-dimsum-parent-slot="dsTabsSubtabButton"]')[index];
122
122
  }
@@ -33,9 +33,12 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
33
33
 
34
34
  // Step 4: Scroll the tab into view (simulating scrollbar interaction)
35
35
  await targetTab.scrollIntoView();
36
- // Step 5: Wait for the tab to be visible in the viewport
37
- await targetTab.waitForDisplayed();
38
- await expect(targetTab).toBeDisplayedInViewport();
36
+ // Step 5: Verify the tab is accessible in the DOM after scrolling.
37
+ // Viewport position checks (toBeDisplayedInViewport / getBoundingClientRect comparisons)
38
+ // are unreliable for carousel tabs: Firefox detects overflow:hidden clipping on the
39
+ // parent and reports elements at the carousel edge as outside the viewport even when
40
+ // they are interactable. toBeDisplayed() validates DOM visibility without that pitfall.
41
+ await expect(targetTab).toBeDisplayed();
39
42
  });
40
43
 
41
44
  it('04: should select a tab by clicking after scrolling', async () => {
@@ -60,8 +63,12 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
60
63
  const firstTab = await DSTabsCO.getTab(1);
61
64
  await firstTab.scrollIntoView();
62
65
 
63
- // Step 10: Verify the first tab is visible again
64
- await expect(firstTab).toBeDisplayedInViewport();
66
+ // Step 10: Verify the first tab is within window bounds (same rationale as test 03)
67
+ const isInViewport = await browser.execute((el) => {
68
+ const rect = el.getBoundingClientRect();
69
+ return rect.left >= 0 && rect.right <= window.innerWidth && rect.top >= 0 && rect.bottom <= window.innerHeight;
70
+ }, firstTab);
71
+ await expect(isInViewport).toBe(true);
65
72
  });
66
73
 
67
74
  it('07: should select the first tab after scrolling back', async () => {
@@ -380,9 +387,9 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
380
387
  });
381
388
 
382
389
  it('06: should click on 4th secondary tab which contains DataTable', async () => {
383
- // Step 13: Click on the 4th subtab
390
+ // Step 13: Click on the 4th subtab via JS to bypass Firefox's carousel click interception
384
391
  const fourthSubtab = await DSTabsCO.getSubtab(4);
385
- await fourthSubtab.click();
392
+ await browser.execute((el) => el.click(), fourthSubtab);
386
393
 
387
394
  // Step 14: Verify the 4th subtab is selected
388
395
  const ariaSelected = await fourthSubtab.getAttribute('aria-selected');
@@ -485,6 +492,10 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
485
492
  it('06: should press Tab to move focus to secondary tabs', async () => {
486
493
  // Step 12: Press Tab to move focus to the subtabs list
487
494
  await browser.keys(Key.Tab);
495
+ if (browser.capabilities.browserName === 'firefox') {
496
+ // Firefox requires an extra Tab to reach the subtab list focus target
497
+ await browser.keys(Key.Tab);
498
+ }
488
499
 
489
500
  // Step 13: Verify focus is on the first subtab
490
501
  const firstSubtab = await DSTabsCO.getSubtab(1);
@@ -530,6 +541,10 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
530
541
  it('10: should press Shift+Tab to move focus back to primary tab', async () => {
531
542
  // Step 22: Press Shift+Tab to move focus back to the primary tab
532
543
  await browser.keys([Key.Shift, Key.Tab]);
544
+ if (browser.capabilities.browserName === 'firefox') {
545
+ // Firefox has an extra focus stop on the subtabs carousel container when exiting
546
+ await browser.keys([Key.Shift, Key.Tab]);
547
+ }
533
548
 
534
549
  // Step 23: Verify focus is back on the third tab
535
550
  const thirdTab = await DSTabsCO.getTab(3);