dimsum-e2e-tests 3.80.0-next.42 → 3.80.0-next.44

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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/ds-accordion/DSAccordionCO.js +4 -4
  3. package/ds-breadcrumb/DSBreadcrumb.visual.spec.js +0 -7
  4. package/ds-breadcrumb/DSBreadcrumbCO.js +18 -3
  5. package/{ds-dialog/axe-core/DSDialog.warning.axe-core.spec.func.js → ds-breadcrumb/slots/DSBreadcrumb.slots.axe-core.func.spec.js} +7 -8
  6. package/ds-breadcrumb/slots/DSBreadcrumb.slots.func.spec.js +38 -0
  7. package/ds-breadcrumb/slots/DSBreadcrumb.slots.visual.spec.js +17 -0
  8. package/ds-chat/DSChatCO.js +20 -0
  9. package/ds-chat/container/visible-elements/DSChat-container.visible-elements.func.spec.js +42 -0
  10. package/ds-chat/loadmore/keep-focus/DSChat-loadmore.keep-focus.func.spec.js +28 -0
  11. package/ds-controlled-form/ds-controlled-radio/DSControlledRadioCO.js +1 -1
  12. package/ds-dialog/DSDialogCO.js +1 -1
  13. package/ds-form-combobox-multi/virtualization/{DSComboboxMulti.virtualization.func.spec .js → DSComboboxMulti.virtualization.func.spec.js} +12 -7
  14. package/ds-form-layout-blocks/form-layout-block-item/DSFormLayoutBlockItemCO.js +1 -1
  15. package/ds-global-header/GlobalHeaderCO.js +1 -1
  16. package/ds-grid/DSGridCO.js +1 -1
  17. package/ds-image/DSImageCO.js +4 -4
  18. package/ds-indeterminate-progress-indicator/DSIndeterminateProgressIndicatorCO.js +1 -1
  19. package/ds-left-navigation-tree/LeftNavigationTreeCO.js +46 -0
  20. package/ds-left-navigation-tree/basic/LeftNavigationTree.aria-contract.func.spec.js +62 -0
  21. package/ds-left-navigation-tree/basic/LeftNavigationTree.axe-core.func.spec.js +28 -0
  22. package/ds-left-navigation-tree/basic/LeftNavigationTree.keyboard.func.spec.js +65 -0
  23. package/ds-leftnavigation/LeftNavigation.func.spec.js +38 -0
  24. package/ds-leftnavigation/LeftNavigationCO.js +20 -0
  25. package/ds-menu-button/DSMenuButtonCO.js +4 -4
  26. package/ds-query-builder/DSQueryBuilderCO.js +0 -2
  27. package/ds-svg/DSSvgCO.js +5 -5
  28. package/ds-tabs/DSTabs.visual.spec.js +3 -1
  29. package/ds-toast/DSToast.visual.spec.js +7 -3
  30. package/ds-toast/DSToastCO.js +1 -1
  31. package/ds-treeview/DSTreeViewCO.js +1 -1
  32. package/ds-typography/DSTypographyCO.js +4 -4
  33. package/helpers.js +35 -47
  34. package/package.json +149 -149
  35. package/paths.js +1 -0
  36. /package/ds-indeterminate-progress-indicator/{DSIndetermintateProgressIndicator.func.spec copy.js → DSIndetermintateProgressIndicator.func.spec.js} +0 -0
@@ -129,3 +129,41 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
129
129
  });
130
130
  });
131
131
  }
132
+
133
+ // DOM-attribute contract: identical in every browser, so it runs on Chrome only
134
+ if (
135
+ (!browser.capabilities['ice:options'].isPhone &&
136
+ !browser.capabilities['ice:options'].isTablet &&
137
+ browser.capabilities.browserName === 'chrome') ||
138
+ browser.capabilities.browserName === 'Chrome'
139
+ ) {
140
+ // Tests for the compliance remediation introduced in PUI-19115 (named slots, new data-testids)
141
+ describe('PUI-19280 - LeftNavigation:: truncated label and open window icon testids - Func', () => {
142
+ before('loading page', async () => {
143
+ const errorOnGo = await LeftNavCO.fullFeatures.go();
144
+ if (errorOnGo) throw errorOnGo;
145
+ });
146
+ it('01: should keep ds-icon-root on open window icons', async () => {
147
+ await (await LeftNavCO.leftNavItem(0)).click();
148
+ await browser.waitUntil(async () => (await LeftNavCO.getOpenWindowIconTestIds()).length > 0, {
149
+ timeoutMsg: 'expected open window icons to be rendered after opening the first item',
150
+ });
151
+ const testIds = await LeftNavCO.getOpenWindowIconTestIds();
152
+ await expect(testIds.every((testId) => testId === 'ds-icon-root')).toBe(true);
153
+ });
154
+ it('02: should show the tooltip testid only while hovering a truncated label', async () => {
155
+ await (await LeftNavCO.leftNavItem(0)).click();
156
+ const truncItem = await LeftNavCO.getTruncatedText(0);
157
+ await truncItem.waitForDisplayed();
158
+ const truncatedTexts = await LeftNavCO.getTruncatedLabelTexts();
159
+ await expect(truncatedTexts[0]).toBe('Exception-1 Truncated Content');
160
+ await expect(await LeftNavCO.getTruncatedLabelTooltip()).not.toBeExisting();
161
+ await mouseOver(truncItem);
162
+ const tooltip = await LeftNavCO.getTruncatedLabelTooltip();
163
+ await tooltip.waitForDisplayed();
164
+ await expect(tooltip).toHaveText('Exception-1 Truncated Content');
165
+ await mouseOver(null, 0, 0);
166
+ await expect(await LeftNavCO.getTruncatedLabelTooltip()).not.toBeExisting();
167
+ });
168
+ });
169
+ }
@@ -78,6 +78,26 @@ export default class LeftNavCO extends PageObject {
78
78
  return $('[data-testid="ds-floating-wrapper-root"]');
79
79
  }
80
80
 
81
+ static async getTruncatedLabelTexts() {
82
+ return browser.execute(() =>
83
+ [...document.querySelectorAll('[data-testid="ds-leftnavigation-truncated-label"]')].map((el) =>
84
+ el.textContent.trim(),
85
+ ),
86
+ );
87
+ }
88
+
89
+ static async getTruncatedLabelTooltip() {
90
+ return $('[data-testid="ds-leftnavigation-truncated-label-tooltip"]');
91
+ }
92
+
93
+ static async getOpenWindowIconTestIds() {
94
+ return browser.execute(() =>
95
+ [...document.querySelectorAll('[data-dimsum-parent-slot="dsLeftnavigationOpenWindowIcon"]')].map(
96
+ (el) => el.dataset.testid,
97
+ ),
98
+ );
99
+ }
100
+
81
101
  static async getSubItemBtn() {
82
102
  return $('[data-testid="sub-item-button"]');
83
103
  }
@@ -3,15 +3,15 @@ import { PageObject, Urlbuilder } from '../helpers';
3
3
 
4
4
  export default class DSMenuButtonCO extends PageObject {
5
5
  // Current supported examples: POC
6
- static activableMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'activable-menu-item');
6
+ static activableMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'activable-menu-item-test');
7
7
 
8
- static multipleSelectMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'multiple-select-menu-item');
8
+ static multipleSelectMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'multiple-select-menu-item-test');
9
9
 
10
10
  static nextTabstopTest = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'next-tabstop-test');
11
11
 
12
- static singleSelectMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'single-select-menu-item');
12
+ static singleSelectMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'single-select-menu-item-test');
13
13
 
14
- static withSubmenuMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'with-submenu-menu-item');
14
+ static withSubmenuMenuItem = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'with-submenu-menu-item-test');
15
15
 
16
16
  static withDisabled = new Urlbuilder(PATH_E2E_MENU_BUTTON, 'disabled-items-test');
17
17
 
@@ -7,8 +7,6 @@ export default class DSQueryBuilderCO extends PageObject {
7
7
 
8
8
  static inModalURL = new Urlbuilder(PATH_E2E_QUERY_BUILDER, 'pui-5837-in-modal');
9
9
 
10
- static advancedDependencies = new Urlbuilder(PATH_QUERY_BUILDER, 'advanced-dependencies');
11
-
12
10
  static arrayConditionsURL = new Urlbuilder(PATH_QUERY_BUILDER, 'advanced-dependencies-array');
13
11
 
14
12
  static fieldDateRangePicker = new Urlbuilder(PATH_QUERY_BUILDER, 'field-date-range-picker');
package/ds-svg/DSSvgCO.js CHANGED
@@ -2,15 +2,15 @@ import { PATH_E2E_SVG } from '../paths';
2
2
  import { PageObject, Urlbuilder } from '../helpers';
3
3
 
4
4
  export default class DSSvgCO extends PageObject {
5
- static basic = new Urlbuilder(PATH_E2E_SVG, 'basic');
5
+ static basic = new Urlbuilder(PATH_E2E_SVG, 'basic-test');
6
6
 
7
- static sizes = new Urlbuilder(PATH_E2E_SVG, 'sizes');
7
+ static sizes = new Urlbuilder(PATH_E2E_SVG, 'sizes-test');
8
8
 
9
- static dimensions = new Urlbuilder(PATH_E2E_SVG, 'dimensions');
9
+ static dimensions = new Urlbuilder(PATH_E2E_SVG, 'dimensions-test');
10
10
 
11
- static insideInteractive = new Urlbuilder(PATH_E2E_SVG, 'inside-interactive-element');
11
+ static insideInteractive = new Urlbuilder(PATH_E2E_SVG, 'inside-interactive-element-test');
12
12
 
13
- static withTooltip = new Urlbuilder(PATH_E2E_SVG, 'with-tooltip');
13
+ static withTooltip = new Urlbuilder(PATH_E2E_SVG, 'with-tooltip-test');
14
14
 
15
15
  // Selectors
16
16
  static async getWrapper() {
@@ -80,7 +80,9 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
80
80
  const snapshot = await browser.checkSnapshot(DSTabsCO.snapshotPath('tab-grid-default'));
81
81
  await expect(snapshot).toEqual(0);
82
82
  });
83
- it('should display tabs with a grid moved one tablist to the right', async () => {
83
+ // Percy intermittently never completes this snapshot (any browser, only when run alongside other snapshots), marks
84
+ // the whole build as failed and rejects every later snapshot. Re-enable once Percy support resolves it.
85
+ it.skip('should display tabs with a grid moved one tablist to the right', async () => {
84
86
  // const tab1 = await DSTabsCO.getTab(1);
85
87
  // await tab1.click();
86
88
  const tab2 = await DSTabsCO.getTab(2);
@@ -153,12 +153,16 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
153
153
  const bottomLeftBtn = await DSToastCO.openToastPositionBtn('bottom-left');
154
154
  const bottomCenterBtn = await DSToastCO.openToastPositionBtn('bottom-center');
155
155
  const bottomRightBtn = await DSToastCO.openToastPositionBtn('bottom-right');
156
- await topLeftBtn.click();
157
- await topCenterBtn.click();
158
- await topRigthBtn.click();
156
+ // Click order matters: all six triggers sit within y 0-88, and the top-* toast containers
157
+ // render over y 13-97 with autoClose disabled. Clicking the top row first covers the bottom
158
+ // row and WebDriver rejects the click as intercepted. Bottom row first keeps every trigger
159
+ // clickable (bottom containers sit at y 983-1067) and yields the same final state.
159
160
  await bottomLeftBtn.click();
160
161
  await bottomCenterBtn.click();
161
162
  await bottomRightBtn.click();
163
+ await topLeftBtn.click();
164
+ await topCenterBtn.click();
165
+ await topRigthBtn.click();
162
166
  await browser.pause(2000);
163
167
  const topLeftToast = await DSToastCO.getToastByPosition('top-left');
164
168
  const topCenterToast = await DSToastCO.getToastByPosition('top-center');
@@ -13,7 +13,7 @@ export default class DSToastCO extends PageObject {
13
13
 
14
14
  static longTextURL = new Urlbuilder(PATH_E2E_TOAST, 'long-text-test');
15
15
 
16
- static longTextWithLinkURL = new Urlbuilder(PATH_E2E_TOAST, 'long-text-with-link');
16
+ static longTextWithLinkURL = new Urlbuilder(PATH_E2E_TOAST, 'long-text-with-link-test');
17
17
 
18
18
  static multipleToastURL = new Urlbuilder(PATH_E2E_TOAST, 'multiple-toast-test');
19
19
 
@@ -17,7 +17,7 @@ export const knobs = {
17
17
  export default class DSTreeViewCO extends PageObject {
18
18
  static basicUrl = new Urlbuilder(PATH_TREEVIEW, 'basic');
19
19
 
20
- static compactURL = new Urlbuilder(PATH_TREEVIEW, 'compact');
20
+ static compactURL = new Urlbuilder(PATH_TREEVIEW, 'compact-view');
21
21
 
22
22
  static fluidHeightURL = new Urlbuilder(PATH_TREEVIEW, 'fluid-height');
23
23
 
@@ -3,13 +3,13 @@ import { PageObject, Urlbuilder, getElementByIndex } from '../helpers';
3
3
 
4
4
  export default class DSTypographyCO extends PageObject {
5
5
  // Desktop
6
- static cardURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'card');
6
+ static cardURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'card-read-more');
7
7
 
8
- static formURl = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'form');
8
+ static formURl = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'form-test');
9
9
 
10
- static dialogURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'dialog');
10
+ static dialogURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'dialog-test');
11
11
 
12
- static showcaseURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'show-case');
12
+ static showcaseURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'show-case-test');
13
13
 
14
14
  static truncationURL = new Urlbuilder(PATH_E2E_TYPOGRAPHY, 'truncation-test');
15
15
 
package/helpers.js CHANGED
@@ -402,66 +402,54 @@ export async function getLocationByDataTestId(dataTest, index) {
402
402
  return result;
403
403
  }
404
404
 
405
+ // Inset from the element's top/bottom edge for the scrollbar click. Classic Windows scrollbars
406
+ // render an arrow button (~17px) at each end: clicking it scrolls a single line, while clicking the
407
+ // track scrolls a full page. Clearing the arrow is what makes a click page instead of nudge.
408
+ const SCROLLBAR_ARROW_INSET = 30;
409
+
405
410
  /**
406
- * Simulates clicks on the scrollbar of an element to scroll its content.
411
+ * Simulates clicks on the scrollbar track of an element to page its content.
407
412
  *
408
- * For "down" direction, it clicks near the bottom of the element; for "up",
409
- * it clicks near the top. A pause is added between pointerDown and pointerUp
410
- * to simulate a more realistic click.
413
+ * For "down" direction it clicks the track near the bottom of the element; for "up", near the top.
414
+ * Both are inset far enough to clear the scrollbar's arrow buttons. A pause is added between
415
+ * pointerDown and pointerUp to simulate a more realistic click.
411
416
  *
412
- * @param {string|object} element - Element or selector for the element containing the scrollbar.
417
+ * @param {string|object} element - Element or selector for the element that scrolls (the one with
418
+ * overflow-y: auto/scroll, not an inner content wrapper).
413
419
  * @param {string} direction - Scroll direction: 'up' or 'down' (default: 'down').
414
420
  * @param {number} clicks - Number of clicks to simulate (default: 1).
415
421
  */
416
422
  export async function clickScrollBar(element, direction = 'down', clicks = 1) {
417
- // If 'element' is a string, treat it as a selector.
418
- let elem = typeof element === 'string' ? await $(element) : element;
419
- if (!elem) {
420
- throw new Error('Element not found.');
423
+ if (direction !== 'up' && direction !== 'down') {
424
+ throw new Error("Invalid direction: choose 'up' or 'down'");
421
425
  }
422
426
 
423
- // Get viewport dimensions to clamp coordinates.
424
- const viewport = await browser.getWindowSize();
427
+ // Page viewport, not browser.getWindowSize(): the latter reports the outer window, which includes
428
+ // the titlebar and toolbar, so clamping against it can yield a y below the page and make
429
+ // performActions fail with "move target out of bounds".
430
+ const viewport = await browser.execute(() => ({ width: window.innerWidth, height: window.innerHeight }));
425
431
 
426
- // Loop to simulate each click.
427
432
  for (let i = 0; i < clicks; i++) {
428
- // Re-fetch the element's current bounding rect.
429
- let rect;
430
- if (typeof elem.getRect === 'function') {
431
- rect = await elem.getRect();
432
- } else {
433
- rect = await browser.execute((el) => {
434
- const r = el.getBoundingClientRect();
435
- return { x: r.x, y: r.y, width: r.width, height: r.height };
436
- }, elem);
433
+ // Re-resolve on every iteration. Virtualized and portalled scrollers re-render between clicks,
434
+ // and a cached element reference would raise "stale element reference".
435
+ const elem = typeof element === 'string' ? await $(element) : element;
436
+ if (!(await elem.isExisting())) {
437
+ throw new Error(`clickScrollBar: element no longer exists on click ${i + 1} of ${clicks}.`);
437
438
  }
438
439
 
439
- // Define element's vertical limits (with a margin of 5px).
440
- const topLimit = Math.round(rect.y + 5);
441
- const bottomLimit = Math.round(rect.y + rect.height - 5);
442
- // Calculate x-coordinate: 5px from the right edge.
443
- let xCoord = Math.round(rect.x + rect.width - 5);
444
- xCoord = Math.max(0, Math.min(xCoord, viewport.width - 1));
445
-
446
- let yCoord;
447
- if (direction === 'down') {
448
- // Para scroll down: queremos hacer click en el área inferior.
449
- // Se puede calcular un offset en función del número de click.
450
- yCoord = bottomLimit - i * 5; // Ajusta el valor (por ejemplo, 5px) según sea necesario.
451
- } else if (direction === 'up') {
452
- // Para scroll up: click en el área superior.
453
- yCoord = topLimit + i * 5; // Ajusta el valor (por ejemplo, 5px) según sea necesario.
454
- } else {
455
- throw new Error("Invalid direction: choose 'up' or 'down'");
456
- }
457
- // Asegurarse de que yCoord esté dentro de los límites del elemento.
458
- if (direction === 'down') {
459
- yCoord = Math.min(yCoord, bottomLimit);
460
- } else {
461
- yCoord = Math.max(yCoord, topLimit);
462
- }
463
- // Clamp yCoord within viewport.
464
- yCoord = Math.max(0, Math.min(yCoord, viewport.height - 1));
440
+ const rect = await browser.execute((el) => {
441
+ const r = el.getBoundingClientRect();
442
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
443
+ }, elem);
444
+
445
+ // x: inside the scrollbar band, 5px from the right edge.
446
+ const xCoord = Math.max(0, Math.min(Math.round(rect.x + rect.width - 5), viewport.width - 1));
447
+
448
+ const inset = Math.min(SCROLLBAR_ARROW_INSET, Math.max(1, Math.round(rect.height / 2) - 1));
449
+ const rawY = direction === 'down' ? rect.y + rect.height - inset : rect.y + inset;
450
+ // Keep the point inside the element, then inside the viewport.
451
+ const boundedY = Math.min(Math.max(Math.round(rawY), Math.round(rect.y) + 1), Math.round(rect.y + rect.height) - 1);
452
+ const yCoord = Math.max(0, Math.min(boundedY, viewport.height - 1));
465
453
 
466
454
  // Perform the click action with a pause to simulate a more realistic manual click.
467
455
  await browser.performActions([