dimsum-e2e-tests 3.70.0-alpha.12 → 3.70.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/ds-accordion/DSAccordionCO.js +5 -5
- package/ds-breadcrumb/DSBreadcrumbCO.js +1 -1
- package/ds-chip/Basic/DSChip.basic.visual.spec.js +74 -0
- package/ds-chip/Shape/DSChip.shape.visual.spec.js +66 -0
- package/ds-chip/inside-popper/DSChip.inside-popper.visual.spec.js +69 -0
- package/ds-controlled-form/ds-controlled-radio/DSControlledRadioCO.js +1 -1
- package/ds-dialog/DSDialogCO.js +1 -1
- package/ds-form-combobox-multi/virtualization/{DSComboboxMulti.virtualization.func.spec .js → DSComboboxMulti.virtualization.func.spec.js} +12 -7
- package/ds-form-date-range-picker/DateRangePicker.visual.spec.js +9 -0
- package/ds-form-layout-blocks/form-layout-block-item/DSFormLayoutBlockItemCO.js +1 -1
- package/ds-global-header/GlobalHeaderCO.js +28 -2
- package/ds-global-header/app-picker-element-ids/GlobalHeader.app-picker-element-ids.func.spec.js +84 -0
- package/ds-global-header/search-toggle-slots/GlobalHeader.search-toggle-slots.func.spec.js +10 -8
- package/ds-global-header/slots/GlobalHeader.slots.visual.spec.js +1 -1
- package/ds-grid/DSGridCO.js +1 -1
- package/ds-image/DSImageCO.js +4 -4
- package/ds-indeterminate-progress-indicator/DSIndeterminateProgressIndicatorCO.js +1 -1
- package/ds-menu-button/DSMenuButtonCO.js +4 -4
- package/ds-query-builder/DSQueryBuilderCO.js +0 -2
- package/ds-svg/DSSvgCO.js +5 -5
- package/ds-tabs/DSTabsCO.js +4 -0
- package/ds-tabs/notification-badge/DSTabs.notification-badge.axe-core.func.spec.js +28 -0
- package/ds-tabs/notification-badge/DSTabs.notification-badge.func.spec.js +51 -0
- package/ds-toast/DSToast.visual.spec.js +7 -3
- package/ds-toast/DSToastCO.js +1 -1
- package/ds-treeview/DSTreeViewCO.js +1 -1
- package/ds-typography/DSTypographyCO.js +4 -4
- package/helpers.js +35 -47
- package/package.json +149 -149
- package/paths.js +4 -0
- package/z-index/ZindexCO.js +4 -0
- package/z-index/dialog-side-panel/ZIndex.dialog-sidepanel.visual.spec.js +7 -1
- package/ds-dialog/axe-core/DSDialog.warning.axe-core.spec.func.js +0 -24
- /package/ds-indeterminate-progress-indicator/{DSIndetermintateProgressIndicator.func.spec copy.js → DSIndetermintateProgressIndicator.func.spec.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 3.70.0-alpha.14 (2026-09-18)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package dimsum-e2e-tests
|
|
9
|
+
|
|
10
|
+
## 3.70.0-alpha.13 (2026-09-17)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- dimsum:: use exact Storybook story ids in e2e page objects [PUI-19184](https://jira.elliemae.io/browse/PUI-19184) ([#8374](https://github.com/intcx/PLATFORM-UI.dimsum/issues/8374)) ([26ef67a](https://github.com/intcx/PLATFORM-UI.dimsum/commit/26ef67a64afc776db4f5cdb90e0ff259de70c6d1))
|
|
15
|
+
|
|
6
16
|
## 3.70.0-alpha.12 (2026-09-03)
|
|
7
17
|
|
|
8
18
|
### Bug Fixes
|
|
@@ -4,13 +4,13 @@ import { PageObject, Urlbuilder, getElementByIndex } from '../helpers';
|
|
|
4
4
|
|
|
5
5
|
export default class DSAccordionCO extends PageObject {
|
|
6
6
|
// Desktop
|
|
7
|
-
static basicURL = new Urlbuilder(PATH_E2E_ACCORDION, 'basic');
|
|
7
|
+
static basicURL = new Urlbuilder(PATH_E2E_ACCORDION, 'basic-test');
|
|
8
8
|
|
|
9
|
-
static multipleURL = new Urlbuilder(PATH_E2E_ACCORDION, 'multiple');
|
|
9
|
+
static multipleURL = new Urlbuilder(PATH_E2E_ACCORDION, 'multiple-test');
|
|
10
10
|
|
|
11
|
-
static toMobileURL = new Urlbuilder(PATH_E2E_ACCORDION, 'desktop-to-mobile');
|
|
11
|
+
static toMobileURL = new Urlbuilder(PATH_E2E_ACCORDION, 'desktop-to-mobile-test');
|
|
12
12
|
|
|
13
|
-
static customActions = new Urlbuilder(PATH_E2E_ACCORDION, 'render-custom-actions');
|
|
13
|
+
static customActions = new Urlbuilder(PATH_E2E_ACCORDION, 'render-custom-actions-test');
|
|
14
14
|
|
|
15
15
|
static headerControls = new Urlbuilder(PATH_E2E_ACCORDION, 'header-control-examples-test');
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ export default class DSAccordionCO extends PageObject {
|
|
|
40
40
|
|
|
41
41
|
static applyAriaDisabled = new Urlbuilder(PATH_E2E_ACCORDION, 'apply-aria-disabled-test');
|
|
42
42
|
|
|
43
|
-
static scrollableContent = new Urlbuilder(PATH_E2E_ACCORDION, 'scrollable-content');
|
|
43
|
+
static scrollableContent = new Urlbuilder(PATH_E2E_ACCORDION, 'scrollable-content-test');
|
|
44
44
|
|
|
45
45
|
static wrapLabel = new Urlbuilder(PATH_E2E_ACCORDION, 'wrap-label');
|
|
46
46
|
|
|
@@ -13,7 +13,7 @@ export default class DSBreadcrumbCO extends PageObject {
|
|
|
13
13
|
|
|
14
14
|
static activeURL = new Urlbuilder(PATH_E2E_BREADCRUMB, 'active-test');
|
|
15
15
|
|
|
16
|
-
static ucTruncatedURL = new Urlbuilder(PATH_E2E_BREADCRUMB, 'bread-crumb-truncated');
|
|
16
|
+
static ucTruncatedURL = new Urlbuilder(PATH_E2E_BREADCRUMB, 'bread-crumb-truncated-test');
|
|
17
17
|
|
|
18
18
|
static containerProps = new Urlbuilder(PATH_E2E_BREADCRUMB, 'container-props-test');
|
|
19
19
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { mouseOver, tabStops } from '../../helpers';
|
|
2
|
+
import DSChipCO from '../DSChipCO';
|
|
3
|
+
|
|
4
|
+
if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
|
|
5
|
+
const PARKED_X = 500;
|
|
6
|
+
const PARKED_Y = 400;
|
|
7
|
+
|
|
8
|
+
describe('PUI-18892 - DSChip:: basic shape, Spec v2 states - visual test', () => {
|
|
9
|
+
before('loading page', async () => {
|
|
10
|
+
const errorOnGo = await DSChipCO.basicURL.go();
|
|
11
|
+
if (errorOnGo) throw errorOnGo;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('01: large chip hovered', async () => {
|
|
15
|
+
await (await DSChipCO.getChipByIndex(0)).waitForDisplayed();
|
|
16
|
+
await mouseOver(await DSChipCO.getChipByIndex(0));
|
|
17
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
18
|
+
await expect(snapshot).toEqual(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('02: large chip focused, not hovered', async () => {
|
|
22
|
+
const chipButton = await (await DSChipCO.getChipByIndex(0)).$('button');
|
|
23
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
24
|
+
await tabStops(2); // chip 0 root wrapper, then chip 0 button
|
|
25
|
+
await expect(chipButton).toBeFocused();
|
|
26
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
27
|
+
await expect(snapshot).toEqual(0);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('03: large chip focused and hovered', async () => {
|
|
31
|
+
const chipButton = await (await DSChipCO.getChipByIndex(0)).$('button');
|
|
32
|
+
await mouseOver(await DSChipCO.getChipByIndex(0));
|
|
33
|
+
await expect(chipButton).toBeFocused();
|
|
34
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
35
|
+
await expect(snapshot).toEqual(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('04: small chip hovered', async () => {
|
|
39
|
+
await mouseOver(await DSChipCO.getChipByIndex(1));
|
|
40
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
41
|
+
await expect(snapshot).toEqual(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('05: selected chip focused, not hovered', async () => {
|
|
45
|
+
const chipButton = await (await DSChipCO.getChipByIndex(2)).$('button');
|
|
46
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
47
|
+
await tabStops(2); // from chip 0 button: chip 1 button, then chip 2 button
|
|
48
|
+
await expect(chipButton).toBeFocused();
|
|
49
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
50
|
+
await expect(snapshot).toEqual(0);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('06: selected chip focused and hovered', async () => {
|
|
54
|
+
const chipButton = await (await DSChipCO.getChipByIndex(2)).$('button');
|
|
55
|
+
await mouseOver(await DSChipCO.getChipByIndex(2));
|
|
56
|
+
await expect(chipButton).toBeFocused();
|
|
57
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
58
|
+
await expect(snapshot).toEqual(0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('07: disabled chip hovered', async () => {
|
|
62
|
+
await mouseOver(await DSChipCO.getChipByIndex(4));
|
|
63
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
64
|
+
await expect(snapshot).toEqual(0);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('08: wrapText chip hovered', async () => {
|
|
68
|
+
const chipButton = await (await DSChipCO.getChipByIndex(5)).$('button');
|
|
69
|
+
await chipButton.moveTo();
|
|
70
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
71
|
+
await expect(snapshot).toEqual(0);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { mouseOver, tabStops } from '../../helpers';
|
|
2
|
+
import DSChipCO from '../DSChipCO';
|
|
3
|
+
|
|
4
|
+
if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
|
|
5
|
+
const PARKED_X = 500;
|
|
6
|
+
const PARKED_Y = 400;
|
|
7
|
+
|
|
8
|
+
describe('PUI-18893 - DSChip:: round shape, Spec v2 states - visual test', () => {
|
|
9
|
+
before('loading page', async () => {
|
|
10
|
+
const errorOnGo = await DSChipCO.shapeURL.go();
|
|
11
|
+
if (errorOnGo) throw errorOnGo;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('01: all round chips at rest', async () => {
|
|
15
|
+
const chip = await DSChipCO.getChipByIndex(0);
|
|
16
|
+
await chip.waitForDisplayed();
|
|
17
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
18
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
19
|
+
await expect(snapshot).toEqual(0);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('02: large round chip hovered', async () => {
|
|
23
|
+
await mouseOver(await DSChipCO.getChipByIndex(0));
|
|
24
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
25
|
+
await expect(snapshot).toEqual(0);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('03: large round chip focused, not hovered', async () => {
|
|
29
|
+
const chipButton = await (await DSChipCO.getChipByIndex(0)).$('button');
|
|
30
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
31
|
+
await tabStops(1); // chip 0 button (no tabIndex on the round chip roots)
|
|
32
|
+
await expect(chipButton).toBeFocused();
|
|
33
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
34
|
+
await expect(snapshot).toEqual(0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('04: large round chip focused and hovered', async () => {
|
|
38
|
+
const chipButton = await (await DSChipCO.getChipByIndex(0)).$('button');
|
|
39
|
+
await mouseOver(await DSChipCO.getChipByIndex(0));
|
|
40
|
+
await expect(chipButton).toBeFocused();
|
|
41
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
42
|
+
await expect(snapshot).toEqual(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('05: small round chip hovered', async () => {
|
|
46
|
+
await mouseOver(await DSChipCO.getChipByIndex(1));
|
|
47
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
48
|
+
await expect(snapshot).toEqual(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('06: selected round chip focused, not hovered', async () => {
|
|
52
|
+
const chipButton = await (await DSChipCO.getChipByIndex(2)).$('button');
|
|
53
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
54
|
+
await tabStops(2); // from chip 0 button: chip 1 button, then chip 2 button
|
|
55
|
+
await expect(chipButton).toBeFocused();
|
|
56
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
57
|
+
await expect(snapshot).toEqual(0);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('07: disabled round chip hovered', async () => {
|
|
61
|
+
await mouseOver(await DSChipCO.getChipByIndex(4));
|
|
62
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
63
|
+
await expect(snapshot).toEqual(0);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { mouseOver, tabStops } from '../../helpers';
|
|
2
|
+
import DSChipCO from '../DSChipCO';
|
|
3
|
+
|
|
4
|
+
if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
|
|
5
|
+
const PARKED_X = 900;
|
|
6
|
+
const PARKED_Y = 700;
|
|
7
|
+
|
|
8
|
+
// Covers the Spec v2 implementation shipped in PUI-17972 (Implement Spec v2 for Chip component)
|
|
9
|
+
describe('PUI-18992 - DSChip:: inside popper, Spec v2 states - visual test', () => {
|
|
10
|
+
before('loading page', async () => {
|
|
11
|
+
const errorOnGo = await DSChipCO.popperURL.go();
|
|
12
|
+
if (errorOnGo) throw errorOnGo;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('01: chips rendered inside the open popover, first chip focused on open', async () => {
|
|
16
|
+
const popperTrigger = await DSChipCO.getPopperTrigger();
|
|
17
|
+
await popperTrigger.click();
|
|
18
|
+
const chip = await DSChipCO.getChipByIndex(0);
|
|
19
|
+
await chip.waitForDisplayed();
|
|
20
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
21
|
+
// the story focuses the first chip on open, so this frame is both the idle-open
|
|
22
|
+
// state and the focus-on-open state — one snapshot covers both
|
|
23
|
+
await expect(await chip.$('button')).toBeFocused();
|
|
24
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
25
|
+
await expect(snapshot).toEqual(0);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('02: first chip focused and hovered', async () => {
|
|
29
|
+
const chipButton = await (await DSChipCO.getChipByIndex(0)).$('button');
|
|
30
|
+
await mouseOver(await DSChipCO.getChipByIndex(0));
|
|
31
|
+
await expect(chipButton).toBeFocused();
|
|
32
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
33
|
+
await expect(snapshot).toEqual(0);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('03: second chip focused, not hovered', async () => {
|
|
37
|
+
const chipButton = await (await DSChipCO.getChipByIndex(1)).$('button');
|
|
38
|
+
await mouseOver(null, PARKED_X, PARKED_Y);
|
|
39
|
+
await tabStops(1); // from chip 0 button to chip 1 button — no chip here opts into a root tab stop
|
|
40
|
+
await expect(chipButton).toBeFocused();
|
|
41
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
42
|
+
await expect(snapshot).toEqual(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('04: unfocused chip hovered', async () => {
|
|
46
|
+
await mouseOver(await DSChipCO.getChipByIndex(3));
|
|
47
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
48
|
+
await expect(snapshot).toEqual(0);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('05: truncated chip expands its label on hover', async () => {
|
|
52
|
+
await mouseOver(await DSChipCO.getChipByIndex(7));
|
|
53
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
54
|
+
await expect(snapshot).toEqual(0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('06: long label chip hovered', async () => {
|
|
58
|
+
await mouseOver(await DSChipCO.getChipByIndex(2));
|
|
59
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
60
|
+
await expect(snapshot).toEqual(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('07: disabled chip hovered', async () => {
|
|
64
|
+
await mouseOver(await DSChipCO.getChipByIndex(4));
|
|
65
|
+
const snapshot = await browser.percyCheckScreenshot();
|
|
66
|
+
await expect(snapshot).toEqual(0);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
@@ -14,7 +14,7 @@ export default class DSControlledRadioCO extends PageObject {
|
|
|
14
14
|
|
|
15
15
|
static applyAriaDisabled = new Urlbuilder(PATH_E2E_RADIO, 'apply-aria-disabled-test');
|
|
16
16
|
|
|
17
|
-
static wrapLabel = new Urlbuilder(PATH_E2E_RADIO, 'wrap-label');
|
|
17
|
+
static wrapLabel = new Urlbuilder(PATH_E2E_RADIO, 'wrap-label-text-test');
|
|
18
18
|
|
|
19
19
|
static themeFontURL = new Urlbuilder(PATH_E2E_RADIO, 'theme-font-family-test');
|
|
20
20
|
|
package/ds-dialog/DSDialogCO.js
CHANGED
|
@@ -4,7 +4,7 @@ import { PATH_E2E_DIALOG } from '../paths';
|
|
|
4
4
|
import { PageObject, Urlbuilder } from '../helpers';
|
|
5
5
|
|
|
6
6
|
export default class DSDialog extends PageObject {
|
|
7
|
-
static basicURL = new Urlbuilder(PATH_E2E_DIALOG, 'basic');
|
|
7
|
+
static basicURL = new Urlbuilder(PATH_E2E_DIALOG, 'basic-test');
|
|
8
8
|
|
|
9
9
|
static centeredURL = new Urlbuilder(PATH_E2E_DIALOG, 'centered-test');
|
|
10
10
|
|
|
@@ -8,21 +8,26 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
|
|
|
8
8
|
const errorOnGo = await DSComboboxMultiCO.hundredAndOneOptions.go();
|
|
9
9
|
if (errorOnGo) throw errorOnGo;
|
|
10
10
|
});
|
|
11
|
+
// Scroll target must be the fast-list, not getComboListbox(). The latter resolves to the
|
|
12
|
+
// virtualized inner list, which is 3137px tall and starts above the viewport, so coordinates
|
|
13
|
+
// derived from its rect land outside the menu. The fast-list is the element that actually
|
|
14
|
+
// scrolls (overflow-y: auto, 300px tall). One scrollbar-track click pages by ~300px, and the
|
|
15
|
+
// menu opens pre-scrolled to the middle, so three clicks reach either target.
|
|
16
|
+
const scrollBarTarget = '[data-testid="ds-combobox-fast-list"]';
|
|
17
|
+
|
|
11
18
|
it('01: Scroll up by clicking the scrollbar', async () => {
|
|
12
19
|
await DSComboboxMultiCO.openMenuListMouse();
|
|
13
20
|
const listItem34 = await DSComboboxMultiCO.getOptionByLabel('label-34');
|
|
14
21
|
await expect(listItem34).not.toBeDisplayedInViewport();
|
|
15
|
-
|
|
16
|
-
await clickScrollBar(comboboxListBox, 'up', 5);
|
|
22
|
+
await clickScrollBar(scrollBarTarget, 'up', 3);
|
|
17
23
|
await expect(listItem34).toBeDisplayedInViewport();
|
|
18
24
|
});
|
|
19
25
|
it('02: Scroll down by clicking the scrollbar', async () => {
|
|
20
26
|
await DSComboboxMultiCO.openMenuListMouse();
|
|
21
|
-
const
|
|
22
|
-
await expect(
|
|
23
|
-
|
|
24
|
-
await
|
|
25
|
-
await expect(listItem75).toBeDisplayedInViewport();
|
|
27
|
+
const listItem85 = await DSComboboxMultiCO.getOptionByLabel('label-85');
|
|
28
|
+
await expect(listItem85).not.toBeDisplayedInViewport();
|
|
29
|
+
await clickScrollBar(scrollBarTarget, 'down', 3);
|
|
30
|
+
await expect(listItem85).toBeDisplayedInViewport();
|
|
26
31
|
});
|
|
27
32
|
});
|
|
28
33
|
}
|
|
@@ -26,11 +26,20 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
|
|
|
26
26
|
await browser.eyesOpen();
|
|
27
27
|
const day = await DateRangePickerCO.getDayOnCalendarByIndex(20);
|
|
28
28
|
await day.click();
|
|
29
|
+
/*
|
|
30
|
+
* The pick that completes the range closes the calendar and returns focus to the trigger
|
|
31
|
+
* (PUI-15572, WCAG 3.2.2 On Input). Reopen it so the snapshot shows the selected range
|
|
32
|
+
* highlighted inside the calendar, and so the following tests still have it open.
|
|
33
|
+
*/
|
|
34
|
+
const reopenDatePicker = await DateRangePickerCO.getPickerBtn();
|
|
35
|
+
await reopenDatePicker.click();
|
|
29
36
|
const snapshot = await browser.eyesCheckSnapshot(DateRangePickerCO.snapshotPath('date-range-picker-two-date'));
|
|
30
37
|
await expect(snapshot).toEqual(0);
|
|
31
38
|
});
|
|
32
39
|
it('04: should display contr. date range picker open and with long range end', async () => {
|
|
33
40
|
await browser.eyesOpen();
|
|
41
|
+
// reopening in test 03 reset the next pick to "from", so this pick auto-orders into a
|
|
42
|
+
// cross-month range and leaves the calendar open instead of closing it
|
|
34
43
|
const nextMonthArrow = await DateRangePickerCO.getNextMonthBtn();
|
|
35
44
|
await nextMonthArrow.click();
|
|
36
45
|
const day = await DateRangePickerCO.getDayOnCalendarByIndex(10);
|
|
@@ -7,7 +7,7 @@ export default class DSFormLayoutBlockItemCO extends PageObject {
|
|
|
7
7
|
|
|
8
8
|
static basicTestURL = new Urlbuilder(PATH_E2E_FORM_LAYOUT_BLOCK_ITEM, 'basic-test');
|
|
9
9
|
|
|
10
|
-
static withHighlight = new Urlbuilder(PATH_E2E_FORM_LAYOUT_BLOCK_ITEM, 'with-highlight');
|
|
10
|
+
static withHighlight = new Urlbuilder(PATH_E2E_FORM_LAYOUT_BLOCK_ITEM, 'with-highlight-e-2-e');
|
|
11
11
|
|
|
12
12
|
static withCustomHighlight = new Urlbuilder(PATH_E2E_FORM_LAYOUT_BLOCK_ITEM, 'custom-highlight-test');
|
|
13
13
|
|
|
@@ -3,7 +3,7 @@ import { PATH_E2E_GLOBAL_HEADER, PATH_E2E_GLOBAL_HEADER_PUI18647 } from '../path
|
|
|
3
3
|
import { PageObject, Urlbuilder, getElementByIndex, type } from '../helpers';
|
|
4
4
|
|
|
5
5
|
export default class GlobalHeader extends PageObject {
|
|
6
|
-
static basicURL = new Urlbuilder(PATH_E2E_GLOBAL_HEADER, 'basic');
|
|
6
|
+
static basicURL = new Urlbuilder(PATH_E2E_GLOBAL_HEADER, 'basic-test');
|
|
7
7
|
|
|
8
8
|
static oneTab = new Urlbuilder(PATH_E2E_GLOBAL_HEADER, 'one-tab');
|
|
9
9
|
|
|
@@ -153,6 +153,32 @@ export default class GlobalHeader extends PageObject {
|
|
|
153
153
|
return $('[data-testid="pui18647-gh-apppicker-trigger-component"]');
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
// PUI-18985 selectors
|
|
157
|
+
|
|
158
|
+
// The out-of-the-box trigger the item renders when it supplies no custom one. Anchored on the
|
|
159
|
+
// accessible name, not on the testid alone: `gh-toolbar-item` is shared by every toolbar item type.
|
|
160
|
+
static async getAppPickerDefaultTrigger() {
|
|
161
|
+
return $('[data-testid="gh-toolbar-item"][aria-label="Apps"]');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Elements carrying a given id. Returned as a collection rather than a single element so a caller
|
|
165
|
+
// can assert BOTH that a reference resolves and that it resolves exactly once — an id present twice
|
|
166
|
+
// is a broken document, and `getElementById`/`querySelector`/every `aria-*` reference would
|
|
167
|
+
// silently take the first match and hide it.
|
|
168
|
+
static async getElementsById(id) {
|
|
169
|
+
return $$(`[id="${id}"]`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Every duplicated id in the page. Read across the whole document rather than probed id by id: the
|
|
173
|
+
// defect this guards against emitted one extra id as a side effect of being given one, so the
|
|
174
|
+
// assertion has to be able to see ids the test never named.
|
|
175
|
+
static async getDuplicateElementIds() {
|
|
176
|
+
return browser.execute(() => {
|
|
177
|
+
const ids = Array.from(document.querySelectorAll('[id]'), (node) => node.id);
|
|
178
|
+
return [...new Set(ids.filter((id, index) => ids.indexOf(id) !== index))];
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
156
182
|
// The popup-menu item's own root. Before PUI-18647 this element was an unstyled wrapper with no
|
|
157
183
|
// slot and no data-testid, so the item as a whole had no injection point.
|
|
158
184
|
static async getPopupMenuContainer() {
|
|
@@ -170,7 +196,7 @@ export default class GlobalHeader extends PageObject {
|
|
|
170
196
|
// The search-toggle item's root container. Item-level global attributes land HERE for this item
|
|
171
197
|
// type, not on the trigger button as with the sibling types.
|
|
172
198
|
static async getSearchToggleContainer() {
|
|
173
|
-
return $('[data-testid="ds-
|
|
199
|
+
return $('[data-testid="ds-global-header-menubar-item-searchtoggle-container"]');
|
|
174
200
|
}
|
|
175
201
|
|
|
176
202
|
static async getSearchTogglePrevButton() {
|
package/ds-global-header/app-picker-element-ids/GlobalHeader.app-picker-element-ids.func.spec.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import DSAppPickerCO from '../../ds-apppicker/DSAppPickerCO';
|
|
2
|
+
import GlobalHeaderCO from '../GlobalHeaderCO';
|
|
3
|
+
|
|
4
|
+
// Tests for the fix in PUI-18985. With the app picker expanded from the toolbar, axe reported
|
|
5
|
+
// `aria-dialog-name` (serious): the panel is a `role="dialog"` whose `aria-labelledby` pointed at a
|
|
6
|
+
// generated trigger id while the trigger itself carried the bare item id — a reference to no element,
|
|
7
|
+
// so the dialog had no accessible name at all.
|
|
8
|
+
//
|
|
9
|
+
// The cause was in DSAppPicker rather than the header. The item `id` rode along in the item-level
|
|
10
|
+
// global attributes and was spread onto the trigger AFTER the id DSAppPicker had supplied, which both
|
|
11
|
+
// broke the reference and emitted the same id twice. DSAppPicker now owns every id in the widget and
|
|
12
|
+
// derives them all from one value, and GlobalHeader hands the item id over through that route only.
|
|
13
|
+
//
|
|
14
|
+
// What QA has to know: the consumer's bare id moved OFF the trigger and ONTO the picker root. Suites
|
|
15
|
+
// that selected the trigger by the bare item id migrate to `getIdForAppPickerTrigger(id)`, exported by
|
|
16
|
+
// ds-app-picker. The suffix VALUES are pinned once, in that package's own unit tests, which is what
|
|
17
|
+
// keeps them renameable without breaking consumers — so this spec asserts the WIRING: that root,
|
|
18
|
+
// trigger and dialog agree, and that the reference resolves.
|
|
19
|
+
//
|
|
20
|
+
// The axe scan is deliberately not repeated here. PUI-12445 test 02 already scans this same story with
|
|
21
|
+
// the panel open, and it is the test that detected the violation.
|
|
22
|
+
//
|
|
23
|
+
// Chrome only: ids and aria-* attributes are identical in every engine. The `|| 'Chrome'` arm is
|
|
24
|
+
// mandatory (BrowserStack capitalises browserName; a lowercase-only guard registers zero tests and
|
|
25
|
+
// still exits 0).
|
|
26
|
+
if (
|
|
27
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
28
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
29
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
30
|
+
browser.capabilities.browserName === 'Chrome'
|
|
31
|
+
) {
|
|
32
|
+
describe('PUI-19156 - GlobalHeader:: app-picker element ids and dialog accessible name - Func', () => {
|
|
33
|
+
// The story's app-picker toolbar item declares `id: 'app-picker'`. Every id below is derived from
|
|
34
|
+
// it, which is the whole point: one value in, a predictable family out.
|
|
35
|
+
const ITEM_ID = 'app-picker';
|
|
36
|
+
const TRIGGER_ID = `${ITEM_ID}-dialog-trigger-btn`;
|
|
37
|
+
|
|
38
|
+
before('loading page', async () => {
|
|
39
|
+
const errorOnGo = await GlobalHeaderCO.basicTestURL.go();
|
|
40
|
+
if (errorOnGo) throw errorOnGo;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('01: should suffix the trigger id and keep the bare item id off it', async () => {
|
|
44
|
+
const trigger = await GlobalHeaderCO.getAppPickerDefaultTrigger();
|
|
45
|
+
await trigger.waitForDisplayed();
|
|
46
|
+
|
|
47
|
+
// The breaking half for QA: the bare item id used to land here.
|
|
48
|
+
await expect(trigger).toHaveAttribute('id', TRIGGER_ID);
|
|
49
|
+
await expect((await GlobalHeaderCO.getElementsById(ITEM_ID)).length).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('02: should land the bare id on the root and name the dialog from the trigger', async () => {
|
|
53
|
+
await (await GlobalHeaderCO.getAppPickerDefaultTrigger()).click();
|
|
54
|
+
const root = await DSAppPickerCO.getAppPickerRoot();
|
|
55
|
+
await root.waitForDisplayed();
|
|
56
|
+
|
|
57
|
+
// The consumer's own value, unchanged, on the root — and nowhere else.
|
|
58
|
+
await expect(root).toHaveAttribute('id', ITEM_ID);
|
|
59
|
+
await expect((await GlobalHeaderCO.getElementsById(ITEM_ID)).length).toBe(1);
|
|
60
|
+
|
|
61
|
+
// The assertion the defect turns on: the reference has to RESOLVE. Reading the attribute's
|
|
62
|
+
// value alone would have passed happily while it pointed at nothing.
|
|
63
|
+
const dialog = await DSAppPickerCO.getFloatingWrapper();
|
|
64
|
+
await expect(dialog).toHaveAttribute('role', 'dialog');
|
|
65
|
+
await expect(dialog).toHaveAttribute('aria-labelledby', TRIGGER_ID);
|
|
66
|
+
await expect((await GlobalHeaderCO.getElementsById(TRIGGER_ID)).length).toBe(1);
|
|
67
|
+
|
|
68
|
+
// Both section headings are derived the same way and label their own group, so the assertion
|
|
69
|
+
// covers the whole id family rather than just the one the violation named.
|
|
70
|
+
const titleIds = await DSAppPickerCO.collect(await DSAppPickerCO.getTitles(), (title) =>
|
|
71
|
+
title.getAttribute('id'),
|
|
72
|
+
);
|
|
73
|
+
await expect(titleIds).toEqual([`${ITEM_ID}-section-title`, `${ITEM_ID}-custom-section-title`]);
|
|
74
|
+
|
|
75
|
+
const groupLabels = await DSAppPickerCO.collect(await DSAppPickerCO.getGroups(), (group) =>
|
|
76
|
+
group.getAttribute('aria-labelledby'),
|
|
77
|
+
);
|
|
78
|
+
await expect(groupLabels).toEqual(titleIds);
|
|
79
|
+
|
|
80
|
+
// The other half of the fix: handing the picker an id used to emit that id twice.
|
|
81
|
+
await expect(await GlobalHeaderCO.getDuplicateElementIds()).toEqual([]);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -7,11 +7,13 @@ import { type } from '../../helpers';
|
|
|
7
7
|
// - (NEW) item-level attributes now land on the item's ROOT CONTAINER, not on the trigger button as
|
|
8
8
|
// with the sibling item types. The type declared that surface on its configuration type and
|
|
9
9
|
// forwarded none of it, so data-public on a search-toggle entry appeared nowhere.
|
|
10
|
-
// - (
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
10
|
+
// - (NOT a rename, after all) that container's data-testid briefly became the auto-generated
|
|
11
|
+
// post-convention `ds-globalheader-...` spelling, because commit 295f110651c dropped its legacy
|
|
12
|
+
// override in constants/index.ts. This spec asserted that value and flagged the change, which is
|
|
13
|
+
// what raised PUI-19020; the override was then restored as a non-breaking-change obligation. The
|
|
14
|
+
// legacy `ds-global-header-menubar-item-searchtoggle-container` is the frozen expectation, and the
|
|
15
|
+
// element itself never changed through any of it — note the slot name below is identical either
|
|
16
|
+
// way, which is precisely why only the identifier needed defending.
|
|
15
17
|
// - (BREAKING) the two spinbutton result-navigation identifiers were INVERTED: the control that
|
|
16
18
|
// triggered NEXT was slotted as PREVIOUS and vice versa. The accessible names were always right,
|
|
17
19
|
// so testid and accessible name now agree. This is the one breaking change for QA here.
|
|
@@ -39,7 +41,7 @@ if (
|
|
|
39
41
|
await expect(container).toHaveAttribute('data-dimsum-slot', 'dsGlobalheaderMenubarItemSearchtoggleContainer');
|
|
40
42
|
|
|
41
43
|
const publicTestIds = await GlobalHeaderCO.getPublicNodeTestIds();
|
|
42
|
-
await expect(publicTestIds).toEqual(['ds-
|
|
44
|
+
await expect(publicTestIds).toEqual(['ds-global-header-menubar-item-searchtoggle-container', 'gh-toolbar-item']);
|
|
43
45
|
|
|
44
46
|
const dsTypedFlag = await GlobalHeaderCO.getDsTypedItemExistFlag();
|
|
45
47
|
await expect(dsTypedFlag).toHaveText('No');
|
|
@@ -51,7 +53,7 @@ if (
|
|
|
51
53
|
|
|
52
54
|
const publicTestIds = await GlobalHeaderCO.getPublicNodeTestIds();
|
|
53
55
|
await expect(publicTestIds).toEqual([
|
|
54
|
-
'ds-
|
|
56
|
+
'ds-global-header-menubar-item-searchtoggle-container',
|
|
55
57
|
'gh-toolbar-item',
|
|
56
58
|
'ds-globalheader-searchtoggle-expanded-content-wrapper',
|
|
57
59
|
'ds-globalheader-searchtoggle-textinput',
|
|
@@ -112,7 +114,7 @@ if (
|
|
|
112
114
|
const lastMatch = await GlobalHeaderCO.getSearchableRowByIndex(4);
|
|
113
115
|
await expect(await GlobalHeaderCO.isRowHighlighted(lastMatch)).toBe(false);
|
|
114
116
|
const publicTestIds = await GlobalHeaderCO.getPublicNodeTestIds();
|
|
115
|
-
await expect(publicTestIds).toEqual(['ds-
|
|
117
|
+
await expect(publicTestIds).toEqual(['ds-global-header-menubar-item-searchtoggle-container', 'gh-toolbar-item']);
|
|
116
118
|
});
|
|
117
119
|
});
|
|
118
120
|
}
|
|
@@ -12,7 +12,7 @@ if (
|
|
|
12
12
|
if (errorOnGo) throw errorOnGo;
|
|
13
13
|
});
|
|
14
14
|
it('01: should display basic GlobalHeadercwith customized slots', async () => {
|
|
15
|
-
await (await GlobalHeader.getGHMenubarItemButtonSlotByIndex(
|
|
15
|
+
await (await GlobalHeader.getGHMenubarItemButtonSlotByIndex(4)).click();
|
|
16
16
|
const snapshot = await browser.checkSnapshot(GlobalHeader.snapshotPath('global-header-slots'));
|
|
17
17
|
await expect(snapshot).toEqual(0);
|
|
18
18
|
});
|
package/ds-grid/DSGridCO.js
CHANGED
|
@@ -35,7 +35,7 @@ export default class DSGridCO extends PageObject {
|
|
|
35
35
|
|
|
36
36
|
static stickyHeaderFooter = new Urlbuilder(PATH_E2E_GRID, 'sticky-header-and-footer-test');
|
|
37
37
|
|
|
38
|
-
static tableReadOnlyURL = new Urlbuilder(PATH_E2E_GRID, 'table-read-only');
|
|
38
|
+
static tableReadOnlyURL = new Urlbuilder(PATH_E2E_GRID, 'table-read-only-test');
|
|
39
39
|
|
|
40
40
|
static tableTest = new Urlbuilder(PATH_E2E_GRID, 'table-test');
|
|
41
41
|
|
package/ds-image/DSImageCO.js
CHANGED
|
@@ -3,13 +3,13 @@ import { PATH_E2E_IMAGE } from '../paths';
|
|
|
3
3
|
import { PageObject, Urlbuilder } from '../helpers';
|
|
4
4
|
|
|
5
5
|
export default class DSImage extends PageObject {
|
|
6
|
-
static basic = new Urlbuilder(PATH_E2E_IMAGE, 'basic');
|
|
6
|
+
static basic = new Urlbuilder(PATH_E2E_IMAGE, 'basic-test');
|
|
7
7
|
|
|
8
|
-
static sizes = new Urlbuilder(PATH_E2E_IMAGE, 'sizes');
|
|
8
|
+
static sizes = new Urlbuilder(PATH_E2E_IMAGE, 'sizes-test');
|
|
9
9
|
|
|
10
|
-
static dimensions = new Urlbuilder(PATH_E2E_IMAGE, 'dimensions');
|
|
10
|
+
static dimensions = new Urlbuilder(PATH_E2E_IMAGE, 'dimensions-test');
|
|
11
11
|
|
|
12
|
-
static insideInteractive = new Urlbuilder(PATH_E2E_IMAGE, 'inside-interactive-element');
|
|
12
|
+
static insideInteractive = new Urlbuilder(PATH_E2E_IMAGE, 'inside-interactive-element-test');
|
|
13
13
|
|
|
14
14
|
static withTooltip = new Urlbuilder(PATH_E2E_IMAGE, 'with-tooltip');
|
|
15
15
|
|
|
@@ -3,7 +3,7 @@ import { PageObject, Urlbuilder } from '../helpers';
|
|
|
3
3
|
|
|
4
4
|
export default class DSIndeterminateProgressIndicatorCO extends PageObject {
|
|
5
5
|
// Desktop
|
|
6
|
-
static basicURL = new Urlbuilder(PATH_E2E_INDETERMINATE_PROGRESS_INDICATOR, 'basic');
|
|
6
|
+
static basicURL = new Urlbuilder(PATH_E2E_INDETERMINATE_PROGRESS_INDICATOR, 'basic-test');
|
|
7
7
|
|
|
8
8
|
static async getComponentWrapper() {
|
|
9
9
|
return $('[data-testid="ds-indeterminate-progress-indicator-wrapper"]');
|
|
@@ -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() {
|