dimsum-e2e-tests 3.70.0-next.48 → 3.70.0-next.50
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-controlled-form/ds-controlled-radio/aria-disabled/DSControlledRadio.aria-disabled.axe-core.func.spec.js +16 -2
- package/ds-controlled-form/ds-controlled-radio/aria-disabled/DSControlledRadio.aria-disabled.func.spec.js +37 -0
- package/ds-data-table-async/DSDataTableCO.js +2 -0
- package/ds-data-table-async/components/HeaderCO.js +15 -0
- package/ds-data-table-async/filter-menu-close/DSDataTable.filter-menu-close.func.spec.js +39 -0
- package/ds-data-table-async/header-affordances/DSDataTable.header-affordances.func.spec.js +92 -0
- package/ds-data-table-async/resizable/DSDataTable.resize-min-clamp.func.spec.js +72 -0
- package/ds-data-table-async/toggle-cell-focus/DSDataTable.toggle-cell-enter-focus.func.spec.js +31 -0
- package/ds-form-date-range-picker/DateRangePicker.axe-core.spec.js +5 -0
- package/ds-form-date-range-picker/DateRangePicker.functional.spec.js +80 -18
- package/ds-form-date-range-picker/DateRangePickerCO.js +6 -0
- package/ds-form-date-time-picker/partial-date-open-focus/DateTimePicker.partial-date-open-focus.func.spec.js +45 -0
- package/ds-form-toggle/DSToggle.func.spec.js +20 -23
- package/ds-form-toggle/DSToggleCO.js +11 -2
- package/ds-global-header/GlobalHeader.announcements.func.spec.js +27 -0
- package/ds-global-header/GlobalHeader.axe-core.func.spec.js +15 -15
- package/ds-global-header/GlobalHeader.func.spec.js +70 -1
- package/ds-global-header/GlobalHeaderCO.js +25 -1
- package/ds-hooks/useFocusStack/DSHook.useFocusStack.func.spec.js +83 -0
- package/ds-shuttle-v2/DSShuttleV2CO.js +4 -0
- package/ds-shuttle-v2/breadcrumb-a11y/DSShuttleV2.breadcrumb-a11y.func.spec.js +43 -0
- package/ds-shuttle-v2/items/DSShuttleV2.items.func.spec.js +4 -2
- package/package.json +149 -150
- package/paths.js +0 -3
- package/ds-hooks/useFocusStack/DSHook.useFocusStack.skipped.js +0 -57
|
@@ -36,8 +36,17 @@ export default class DSToggleCO extends PageObject {
|
|
|
36
36
|
return $$('[data-testid="ds-controlled-toggle-checkbox"]')[index];
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
// The on/off state is exposed semantically via aria-checked on the role="switch"
|
|
40
|
+
// button. Post PUI-16323 the visible ON/OFF label is aria-hidden and purely
|
|
41
|
+
// presentational, so state must be read from aria-checked, not the label text.
|
|
42
|
+
static async getSwitch(index = 0) {
|
|
43
|
+
return $$('button[role="switch"]')[index];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Presentational ON/OFF label (aria-hidden). Targeted via its stable slot
|
|
47
|
+
// data-testid so we can assert the visible text tracks the state.
|
|
48
|
+
static async getStateLabel(index = 0) {
|
|
49
|
+
return $$('[data-testid="ds-formtoggle-text-wrapper"]')[index];
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
static async getTooltip() {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import GlobalHeader from './GlobalHeaderCO';
|
|
2
|
+
|
|
3
|
+
if (
|
|
4
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
5
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
6
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
7
|
+
browser.capabilities.browserName === 'Chrome'
|
|
8
|
+
) {
|
|
9
|
+
describe('PUI-18771 - GlobalHeader: SearchToggle result announcement -Func', () => {
|
|
10
|
+
before(async () => {
|
|
11
|
+
const errorOnGo = await GlobalHeader.withSearchToggleURL.go();
|
|
12
|
+
if (errorOnGo) throw errorOnGo;
|
|
13
|
+
await GlobalHeader.openAndPopulateSearchToggle();
|
|
14
|
+
});
|
|
15
|
+
it('01: search input should expose the accessible name guiding users to the result navigation', async () => {
|
|
16
|
+
const searchInput = await GlobalHeader.getSearchToggleInput();
|
|
17
|
+
await expect(searchInput).toHaveAttribute(
|
|
18
|
+
'aria-label',
|
|
19
|
+
'Search among the content of the page. Press Tab twice to reach the result navigation.',
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
it('02: results spinbutton should announce the total result count after typing', async () => {
|
|
23
|
+
const spinButton = await GlobalHeader.getSearchToggleSpinbutton();
|
|
24
|
+
await expect(spinButton).toHaveAttribute('aria-valuetext', '3 total results');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -19,14 +19,14 @@ if (
|
|
|
19
19
|
await browser.keys(Key.Tab);
|
|
20
20
|
await browser.keys(Key.Tab);
|
|
21
21
|
const result = await axeCoreCheck();
|
|
22
|
-
expect(result
|
|
22
|
+
await expect(result).toHaveLength(0);
|
|
23
23
|
});
|
|
24
24
|
it('02: should have global header with expanded appPicker and pass axe-core scan', async () => {
|
|
25
25
|
await browser.keys(Key.Tab);
|
|
26
26
|
await browser.keys(Key.Enter);
|
|
27
27
|
|
|
28
28
|
const result = await axeCoreCheck();
|
|
29
|
-
expect(result
|
|
29
|
+
await expect(result).toHaveLength(0);
|
|
30
30
|
});
|
|
31
31
|
it('03: should have global header with expanded menu-list and pass axe-core scan', async () => {
|
|
32
32
|
await browser.keys(Key.Escape);
|
|
@@ -34,7 +34,7 @@ if (
|
|
|
34
34
|
await browser.keys(Key.Tab);
|
|
35
35
|
await browser.keys(Key.Enter);
|
|
36
36
|
const result = await axeCoreCheck();
|
|
37
|
-
expect(result
|
|
37
|
+
await expect(result).toHaveLength(0);
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -47,12 +47,12 @@ if (
|
|
|
47
47
|
const globalHeader = await GlobalHeaderCO.getGlobalHeader();
|
|
48
48
|
await globalHeader.waitForDisplayed();
|
|
49
49
|
const result = await axeCoreCheck();
|
|
50
|
-
expect(result
|
|
50
|
+
await expect(result).toHaveLength(0);
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
// Skipped due to defect PUI-17970
|
|
55
|
-
describe
|
|
55
|
+
describe('PUI-12447 - GlobalHeader: toggle search -AxeCore', () => {
|
|
56
56
|
before(async () => {
|
|
57
57
|
const errorOnGo = await GlobalHeaderCO.withSearchToggleURL.go();
|
|
58
58
|
if (errorOnGo) throw errorOnGo;
|
|
@@ -61,19 +61,19 @@ if (
|
|
|
61
61
|
const globalHeader = await GlobalHeaderCO.getGlobalHeader();
|
|
62
62
|
await globalHeader.waitForDisplayed();
|
|
63
63
|
const result = await axeCoreCheck();
|
|
64
|
-
expect(result
|
|
64
|
+
await expect(result).toHaveLength(0);
|
|
65
65
|
});
|
|
66
66
|
it('02: should have global header with toggle-search expanded and pass axe-core scan', async () => {
|
|
67
67
|
const toggleSearch = await GlobalHeaderCO.getGHToolbarItem(0);
|
|
68
68
|
await toggleSearch.click();
|
|
69
69
|
await type('Hola');
|
|
70
70
|
const result = await axeCoreCheck();
|
|
71
|
-
expect(result
|
|
71
|
+
await expect(result).toHaveLength(0);
|
|
72
72
|
});
|
|
73
73
|
it('03: should have global header with populated toggle-search and pass axe-core scan', async () => {
|
|
74
74
|
await type('Hola');
|
|
75
75
|
const result = await axeCoreCheck();
|
|
76
|
-
expect(result
|
|
76
|
+
await expect(result).toHaveLength(0);
|
|
77
77
|
});
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -86,12 +86,12 @@ if (
|
|
|
86
86
|
const globalHeader = await GlobalHeaderCO.getGlobalHeader();
|
|
87
87
|
await globalHeader.waitForDisplayed();
|
|
88
88
|
const result = await axeCoreCheck();
|
|
89
|
-
expect(result
|
|
89
|
+
await expect(result).toHaveLength(0);
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
// Skipped due to defect PUI-17970
|
|
94
|
-
describe
|
|
94
|
+
describe('PUI-18379 - GlobalHeader: with search toggle -AxeCore', () => {
|
|
95
95
|
before(async () => {
|
|
96
96
|
const errorOnGo = await GlobalHeaderCO.withSearchToggleURL.go();
|
|
97
97
|
if (errorOnGo) throw errorOnGo;
|
|
@@ -103,7 +103,7 @@ if (
|
|
|
103
103
|
await expect(toggleSearch).toHaveAttribute('aria-expanded', 'false');
|
|
104
104
|
await expect(toggleSearch).toHaveAttribute('aria-controls');
|
|
105
105
|
const result = await axeCoreCheck();
|
|
106
|
-
expect(result
|
|
106
|
+
await expect(result).toHaveLength(0);
|
|
107
107
|
});
|
|
108
108
|
it('02: should have global header with search toggle expanded and pass axe-core scan', async () => {
|
|
109
109
|
const toggleSearch = await GlobalHeaderCO.getGHToolbarItem(0);
|
|
@@ -111,17 +111,17 @@ if (
|
|
|
111
111
|
await expect(toggleSearch).toHaveAttribute('aria-expanded', 'true');
|
|
112
112
|
await expect(toggleSearch).toHaveAttribute('aria-controls', /^ds-global-header/);
|
|
113
113
|
const result = await axeCoreCheck();
|
|
114
|
-
expect(result
|
|
114
|
+
await expect(result).toHaveLength(0);
|
|
115
115
|
});
|
|
116
116
|
it('03: should have global header with populated search toggle and pass axe-core scan', async () => {
|
|
117
117
|
await type('Labor');
|
|
118
118
|
const result = await axeCoreCheck();
|
|
119
|
-
expect(result
|
|
119
|
+
await expect(result).toHaveLength(0);
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
// Skipped due to defect PUI-17970
|
|
124
|
-
describe
|
|
124
|
+
describe('PUI-16270 - GlobalHeader: Controled with Iframe -AxeCore', () => {
|
|
125
125
|
before(async () => {
|
|
126
126
|
const errorOnGo = await GlobalHeaderCO.iframeURL.go();
|
|
127
127
|
if (errorOnGo) throw errorOnGo;
|
|
@@ -130,7 +130,7 @@ if (
|
|
|
130
130
|
const globalHeader = await GlobalHeaderCO.getGlobalHeader();
|
|
131
131
|
await globalHeader.waitForDisplayed();
|
|
132
132
|
const result = await axeCoreCheck({ extraDisabledRules: ['landmark-one-main'] });
|
|
133
|
-
expect(result
|
|
133
|
+
await expect(result).toHaveLength(0);
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
136
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { Key } from 'webdriverio';
|
|
2
2
|
import GlobalHeader from './GlobalHeaderCO';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Asserts the search-toggle spinbutton reflects the expected selected-result state.
|
|
5
|
+
const expectSelectedResult = async (valuenow, valuetext) => {
|
|
6
|
+
const spinButton = await GlobalHeader.getSearchToggleSpinbutton();
|
|
7
|
+
await expect(spinButton).toHaveAttribute('aria-valuenow', valuenow);
|
|
8
|
+
await expect(spinButton).toHaveAttribute('aria-valuetext', valuetext);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
if (
|
|
12
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
13
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
14
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
15
|
+
browser.capabilities.browserName === 'Chrome'
|
|
16
|
+
) {
|
|
5
17
|
describe('PUI-10036 - GlobalHeader: title and aria attributes', () => {
|
|
6
18
|
before(async () => {
|
|
7
19
|
const errorOnGo = await GlobalHeader.customAttributes.go();
|
|
@@ -80,4 +92,61 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
|
|
|
80
92
|
await expect(firstToolbarItem).not.toBeFocused();
|
|
81
93
|
});
|
|
82
94
|
});
|
|
95
|
+
|
|
96
|
+
// Tests for the fix in PUI-17974 (SearchToggle arrow navigation could not start with ArrowDown nor cycle)
|
|
97
|
+
describe('PUI-18772 - GlobalHeader: SearchToggle result navigation with ArrowDown -Func', () => {
|
|
98
|
+
before(async () => {
|
|
99
|
+
const errorOnGo = await GlobalHeader.withSearchToggleURL.go();
|
|
100
|
+
if (errorOnGo) throw errorOnGo;
|
|
101
|
+
await GlobalHeader.openAndPopulateSearchToggle();
|
|
102
|
+
});
|
|
103
|
+
it('01: should be idle (no result selected) before navigation starts', async () => {
|
|
104
|
+
await expectSelectedResult('0', '3 total results');
|
|
105
|
+
});
|
|
106
|
+
it('02: should start navigation on last result when pressing ArrowDown from idle', async () => {
|
|
107
|
+
await browser.keys(Key.ArrowDown);
|
|
108
|
+
await expectSelectedResult('3', 'result 3 of 3');
|
|
109
|
+
});
|
|
110
|
+
it('03: should move to the previous result on subsequent ArrowDown', async () => {
|
|
111
|
+
await browser.keys(Key.ArrowDown);
|
|
112
|
+
await expectSelectedResult('2', 'result 2 of 3');
|
|
113
|
+
});
|
|
114
|
+
it('04: should reach the first result on ArrowDown', async () => {
|
|
115
|
+
await browser.keys(Key.ArrowDown);
|
|
116
|
+
await expectSelectedResult('1', 'result 1 of 3');
|
|
117
|
+
});
|
|
118
|
+
it('05: should cycle from the first result back to the last on ArrowDown', async () => {
|
|
119
|
+
await browser.keys(Key.ArrowDown);
|
|
120
|
+
await expectSelectedResult('3', 'result 3 of 3');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Tests for the fix in PUI-17974 (SearchToggle arrow navigation could not start with ArrowDown nor cycle)
|
|
125
|
+
describe('PUI-18773 - GlobalHeader: SearchToggle result navigation with ArrowUp -Func', () => {
|
|
126
|
+
// same setup as above; here the ArrowUp navigation is exercised from idle
|
|
127
|
+
before(async () => {
|
|
128
|
+
const errorOnGo = await GlobalHeader.withSearchToggleURL.go();
|
|
129
|
+
if (errorOnGo) throw errorOnGo;
|
|
130
|
+
await GlobalHeader.openAndPopulateSearchToggle();
|
|
131
|
+
});
|
|
132
|
+
it('01: should be idle (no result selected) before navigation starts', async () => {
|
|
133
|
+
await expectSelectedResult('0', '3 total results');
|
|
134
|
+
});
|
|
135
|
+
it('02: should start navigation on the first result when pressing ArrowUp from idle', async () => {
|
|
136
|
+
await browser.keys(Key.ArrowUp);
|
|
137
|
+
await expectSelectedResult('1', 'result 1 of 3');
|
|
138
|
+
});
|
|
139
|
+
it('03: should move to the next result on subsequent ArrowUp', async () => {
|
|
140
|
+
await browser.keys(Key.ArrowUp);
|
|
141
|
+
await expectSelectedResult('2', 'result 2 of 3');
|
|
142
|
+
});
|
|
143
|
+
it('04: should reach the last result on ArrowUp', async () => {
|
|
144
|
+
await browser.keys(Key.ArrowUp);
|
|
145
|
+
await expectSelectedResult('3', 'result 3 of 3');
|
|
146
|
+
});
|
|
147
|
+
it('05: should cycle from the last result back to the first on ArrowUp', async () => {
|
|
148
|
+
await browser.keys(Key.ArrowUp);
|
|
149
|
+
await expectSelectedResult('1', 'result 1 of 3');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
83
152
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable import/no-relative-packages */
|
|
2
2
|
import { PATH_E2E_GLOBAL_HEADER } from '../paths';
|
|
3
|
-
import { PageObject, Urlbuilder } from '../helpers';
|
|
3
|
+
import { PageObject, Urlbuilder, type } from '../helpers';
|
|
4
4
|
|
|
5
5
|
export default class GlobalHeader extends PageObject {
|
|
6
6
|
static basicURL = new Urlbuilder(PATH_E2E_GLOBAL_HEADER, 'basic');
|
|
@@ -84,6 +84,30 @@ export default class GlobalHeader extends PageObject {
|
|
|
84
84
|
return $('button*=Skip');
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
static async getSearchToggleInput() {
|
|
88
|
+
return $('[data-testid="ds-globalheader-searchtoggle-textinput"]');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static async getSearchToggleSpinbutton() {
|
|
92
|
+
return $('[data-testid="ds-globalheader-searchtoggle-spinbutton-text"]');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Opens the search toggle, runs a query, and focuses the populated results spinbutton
|
|
96
|
+
// so result navigation can be exercised. Waits for results to load before returning.
|
|
97
|
+
static async openAndPopulateSearchToggle(searchText = 'Labor') {
|
|
98
|
+
const toggleSearch = await GlobalHeader.getGHToolbarItem(0);
|
|
99
|
+
await toggleSearch.click();
|
|
100
|
+
const searchInput = await GlobalHeader.getSearchToggleInput();
|
|
101
|
+
await searchInput.click();
|
|
102
|
+
await type(searchText);
|
|
103
|
+
const spinButton = await GlobalHeader.getSearchToggleSpinbutton();
|
|
104
|
+
await browser.waitUntil(async () => (await spinButton.getText()) !== 'n/a', {
|
|
105
|
+
timeout: 3000,
|
|
106
|
+
timeoutMsg: 'search results did not populate after typing',
|
|
107
|
+
});
|
|
108
|
+
await spinButton.click();
|
|
109
|
+
}
|
|
110
|
+
|
|
87
111
|
// Slots
|
|
88
112
|
|
|
89
113
|
static async getGHBreadcrumbChevronlotByIndex(index = 0) {
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
import { Key } from 'webdriverio';
|
|
3
|
+
import useFocusStackCO from './useFocusStackCO';
|
|
4
|
+
import { tabStops } from '../../helpers';
|
|
5
|
+
import DSPillsV2CO from '../../ds-pills-v2/DSPillsV2CO';
|
|
6
|
+
import DSButtonV3CO from '../../ds-button-v3/DSButtonV3CO';
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
10
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
11
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
12
|
+
browser.capabilities.browserName === 'Chrome'
|
|
13
|
+
) {
|
|
14
|
+
describe('PUI-13147: UseFocusStack for focus return -Func', () => {
|
|
15
|
+
before(async () => {
|
|
16
|
+
const errorOnGo = await useFocusStackCO.basicURL.go();
|
|
17
|
+
if (errorOnGo) throw errorOnGo;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('01: should Tab x4 and have D focused', async () => {
|
|
21
|
+
await tabStops(4);
|
|
22
|
+
const typographys = (await useFocusStackCO.getTypographys()).length;
|
|
23
|
+
const pillD = await DSPillsV2CO.getCloseButtonByIndex(3);
|
|
24
|
+
// stack holds the three departed elements [C, B, A] -> 1 (h3) + 3
|
|
25
|
+
await expect(typographys).toEqual(4);
|
|
26
|
+
await expect(pillD).toBeFocused();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('02: PUI-13301 - should click non-focused C, remove it, and keep focus on D (not B)', async () => {
|
|
30
|
+
// D is focused; click C (index 2) to remove it. Focus must return to D, the pre-click element.
|
|
31
|
+
const pillC = await DSPillsV2CO.getCloseButtonByIndex(2);
|
|
32
|
+
await pillC.click();
|
|
33
|
+
// C is gone, so the remaining pills are A, B, D, E, F, G -> D is now at index 2.
|
|
34
|
+
const pillD = await DSPillsV2CO.getCloseButtonByIndex(2);
|
|
35
|
+
const typographys = (await useFocusStackCO.getTypographys()).length;
|
|
36
|
+
// removed C does not linger; the stack reads [B, A] -> 1 (h3) + 2
|
|
37
|
+
await expect(typographys).toEqual(3);
|
|
38
|
+
await expect(pillD).toBeFocused();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('03: should Tab forward to E, remove it, and return focus to D', async () => {
|
|
42
|
+
await tabStops(1);
|
|
43
|
+
const pillE = await DSPillsV2CO.getCloseButtonByIndex(3);
|
|
44
|
+
await expect(pillE).toBeFocused();
|
|
45
|
+
// remove the focused pill with the keyboard
|
|
46
|
+
await browser.keys(Key.Return);
|
|
47
|
+
// E removed, remaining pills are A, B, D, F, G -> D is at index 2
|
|
48
|
+
const pillD = await DSPillsV2CO.getCloseButtonByIndex(2);
|
|
49
|
+
const typographys = (await useFocusStackCO.getTypographys()).length;
|
|
50
|
+
await expect(typographys).toEqual(3);
|
|
51
|
+
await expect(pillD).toBeFocused();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('04: should delete back through the stack until focus falls back to Reset', async () => {
|
|
55
|
+
// remove D (focused) -> B, remove B -> A, remove A -> no survivor left -> fallBackRef (Reset)
|
|
56
|
+
await browser.keys(Key.Return);
|
|
57
|
+
await browser.keys(Key.Return);
|
|
58
|
+
await browser.keys(Key.Return);
|
|
59
|
+
const reset = await DSButtonV3CO.getButtonByIndex(0);
|
|
60
|
+
const typographys = (await useFocusStackCO.getTypographys()).length;
|
|
61
|
+
// stack emptied -> only the h3 remains
|
|
62
|
+
await expect(typographys).toEqual(1);
|
|
63
|
+
await expect(reset).toBeFocused();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('05: should click Reset and restore all removable pills', async () => {
|
|
67
|
+
await browser.keys(Key.Return);
|
|
68
|
+
const closeButtons = await DSPillsV2CO.getCloseButtons();
|
|
69
|
+
const typographys = (await useFocusStackCO.getTypographys()).length;
|
|
70
|
+
await expect(closeButtons).toHaveLength(7);
|
|
71
|
+
await expect(typographys).toEqual(1);
|
|
72
|
+
});
|
|
73
|
+
it('06: should mouse-remove E with an empty stack and fall back focus to Reset', async () => {
|
|
74
|
+
const pillE = await DSPillsV2CO.getCloseButtonByIndex(4);
|
|
75
|
+
await pillE.click();
|
|
76
|
+
const reset = await DSButtonV3CO.getButtonByIndex(0);
|
|
77
|
+
await expect(reset).toBeFocused();
|
|
78
|
+
// E is hidden, so 6 removable pills remain.
|
|
79
|
+
const closeButtons = await DSPillsV2CO.getCloseButtons();
|
|
80
|
+
await expect(closeButtons).toHaveLength(6);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -42,6 +42,8 @@ export default class DSShuttleV2CO extends PageObject {
|
|
|
42
42
|
|
|
43
43
|
static basicURL = new Urlbuilder(PATH_E2E_SHUTTLE_V2, 'basic-test');
|
|
44
44
|
|
|
45
|
+
static breadcrumbAccessibleURL = new Urlbuilder(PATH_E2E_SHUTTLE_V2, 'breadcrumb-accessible-test');
|
|
46
|
+
|
|
45
47
|
static adHocRenderAfterBulkMove = new Urlbuilder(PATH_E2E_SHUTTLE_V2, 'ad-hoc-render-after-bulk-move');
|
|
46
48
|
|
|
47
49
|
static ariaPropsUrl = new Urlbuilder(PATH_E2E_SHUTTLE_V2, 'aria-props-test');
|
|
@@ -192,6 +194,8 @@ export default class DSShuttleV2CO extends PageObject {
|
|
|
192
194
|
|
|
193
195
|
static getBreadcrumbs = async () => $$(`[data-testid="ds-breadcrumb-link"]`);
|
|
194
196
|
|
|
197
|
+
static getActiveBreadcrumb = async () => $(`[data-testid="ds-breadcrumb-link"][aria-current="step"]`);
|
|
198
|
+
|
|
195
199
|
static getSubtitleByItem = async (item) => item.$$(`p`)[1];
|
|
196
200
|
|
|
197
201
|
static getActionButtonByItemAndIndex = async (item, index = 0) =>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import DSShuttleV2CO from '../DSShuttleV2CO';
|
|
2
|
+
|
|
3
|
+
// Tests for the fix introduced in PUI-17395 (ShuttleV2 breadcrumb a11y):
|
|
4
|
+
// every step renders as a focusable <button> and the active/current step exposes
|
|
5
|
+
// aria-current="step". DOM-attribute assertions are browser-agnostic, so this runs Chrome-only.
|
|
6
|
+
if (
|
|
7
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
8
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
9
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
10
|
+
browser.capabilities.browserName === 'Chrome'
|
|
11
|
+
) {
|
|
12
|
+
describe('PUI-18762 - DSShuttleV2:: breadcrumb active step aria-current -Func', () => {
|
|
13
|
+
before(async () => {
|
|
14
|
+
const errorOnGo = await DSShuttleV2CO.breadcrumbAccessibleURL.go();
|
|
15
|
+
if (errorOnGo) throw errorOnGo;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('01: active step exposes aria-current="step" and every step is a focusable button', async () => {
|
|
19
|
+
// Drill down two levels so the breadcrumb has multiple steps (ancestors + current)
|
|
20
|
+
const rootItem = await DSShuttleV2CO.getItemFromSourceByIndex(1);
|
|
21
|
+
await (await DSShuttleV2CO.getActionButtonByItemAndIndex(rootItem, 0)).click();
|
|
22
|
+
const subItem = await DSShuttleV2CO.getItemFromSourceByIndex(2);
|
|
23
|
+
await (await DSShuttleV2CO.getActionButtonByItemAndIndex(subItem, 0)).click();
|
|
24
|
+
|
|
25
|
+
// Gather elements/values
|
|
26
|
+
const crumbs = await DSShuttleV2CO.getBreadcrumbs();
|
|
27
|
+
const activeCrumb = await DSShuttleV2CO.getActiveBreadcrumb();
|
|
28
|
+
const activeCrumbTag = await activeCrumb.getTagName();
|
|
29
|
+
const firstCrumb = crumbs[0];
|
|
30
|
+
const firstCrumbTag = await firstCrumb.getTagName();
|
|
31
|
+
|
|
32
|
+
// Assertions
|
|
33
|
+
await expect(crumbs.length).toBeGreaterThan(1);
|
|
34
|
+
// The current/active step (last) is announced as the current step
|
|
35
|
+
await expect(activeCrumb).toBeExisting();
|
|
36
|
+
await expect(activeCrumb).toHaveAttribute('aria-current', 'step');
|
|
37
|
+
await expect(activeCrumbTag).toBe('button');
|
|
38
|
+
// Non-active ancestor steps are buttons without aria-current
|
|
39
|
+
await expect(firstCrumbTag).toBe('button');
|
|
40
|
+
await expect(firstCrumb).not.toHaveAttribute('aria-current');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -74,11 +74,13 @@ if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:o
|
|
|
74
74
|
it('01: should not move the item when the disabled move action button is clicked', async () => {
|
|
75
75
|
const testItem = await DSShuttleV2CO.getItemWrapper(1);
|
|
76
76
|
const testItemMoveBtn = await DSShuttleV2CO.getActionButtonByItemAndIndex(testItem, 1);
|
|
77
|
-
const testItemMoveBtnDisabled = await testItemMoveBtn.getAttribute('aria-disabled');
|
|
78
77
|
const testItemText = await testItem.getText();
|
|
79
78
|
await testItemMoveBtn.click();
|
|
80
79
|
await expect(testItemText).toBe('Source 0.1');
|
|
81
|
-
|
|
80
|
+
// PUI-17909: a natively disabled DSButton emits the native `disabled` attribute and
|
|
81
|
+
// intentionally omits aria-disabled (that is reserved for applyAriaDisabled). Assert the
|
|
82
|
+
// native disabled state instead of the now-absent aria-disabled.
|
|
83
|
+
await expect(testItemMoveBtn).toBeDisabled();
|
|
82
84
|
});
|
|
83
85
|
it('02: should not display the BAB when a disabled item is clicked', async () => {
|
|
84
86
|
const testItem = await DSShuttleV2CO.getItemWrapper(1);
|