dimsum-e2e-tests 3.80.0-next.4 → 3.80.0-next.40
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 +164 -0
- package/DSStorybook/baseline.js +0 -186
- package/ds-accordion/DSAccordion.visual.spec.js +0 -14
- package/ds-accordion/DSAccordionCO.js +0 -2
- package/ds-apppicker/aria-disabled/DSAppPicker.aria-disabled.visual.spec.js +14 -1
- package/ds-apppicker/basic/DSAppPicker.basic.visual.spec.js +12 -7
- package/ds-banner/DSBanner.text-resize.visual.spec.js +2 -0
- package/ds-banner/DSBanner.text-wrapping.visual.spec.js +3 -6
- package/ds-banner/DSBanner.visual.spec.js +7 -8
- package/ds-banner/DSBannerCO.js +189 -4
- package/ds-banner/aria-and-role/DSBanner.aria-and-role.func.spec.js +113 -2
- package/ds-banner/ids/DSBanner.ids.func.spec.js +66 -0
- package/ds-banner/live-region-lang-dir/DSBanner.live-region-lang-dir.func.spec.js +54 -0
- package/ds-banner/slide-animation/DSBanner.slide-animation.func.spec.js +105 -0
- package/ds-banner/slots/DSBanner.slots.axe-core.func.spec.js +24 -0
- package/ds-banner/slots/DSBanner.slots.func.spec.js +13 -0
- package/ds-banner/slots/DSBanner.slots.visual.spec.js +3 -2
- package/ds-banner/title-element/DSBanner.title-element.func.spec.js +29 -0
- package/ds-chip/DSChip.axe-core.func.spec.js +0 -17
- package/ds-chip/DSChip.visual.spec.js +0 -22
- package/ds-chip/DSChipCO.js +0 -6
- package/ds-fast-list/DSFastListCO.js +37 -0
- package/ds-fast-list/basic/DSFastList.basic.axe-core.func.spec.js +28 -0
- package/ds-fast-list/basic/DSFastList.basic.visual.spec.js +23 -0
- package/ds-fast-list/scroll-to-index/DSFastList.scroll-to-index.func.spec.js +45 -0
- package/ds-indeterminate-progress-indicator/DSIndeterminateProgressIndicatorCO.js +4 -0
- package/ds-indeterminate-progress-indicator/accessible-name/DSIndeterminateProgressIndicator.accessible-name.func.spec.js +51 -0
- package/ds-leftnavigation/LeftNavigation.fullFeatures.axe-core.func.spec.js +37 -0
- package/ds-leftnavigation/LeftNavigation.isSkeleton.axe-core.func.spec.js +23 -0
- package/ds-leftnavigation/LeftNavigation.keepingItems.axe-core.func.spec.js +34 -0
- package/ds-leftnavigation/LeftNavigation.loadingIndicator.axe-core.func.spec.js +41 -0
- package/ds-leftnavigation/LeftNavigation.notificationBadge.axe-core.func.spec.js +21 -0
- package/ds-leftnavigation/LeftNavigation.searchBar.axe-core.func.spec.js +26 -0
- package/ds-leftnavigation/LeftNavigation.showCase.axe-core.func.spec.js +23 -0
- package/ds-leftnavigation/LeftNavigation.tooltip.axe-core.func.spec.js +28 -0
- package/ds-leftnavigation/LeftNavigation.wrappedText.axe-core.func.spec.js +27 -0
- package/ds-modal-slide/inside-dialog/ModalSlide.insideDialog.func.spec.js +45 -0
- package/ds-panel-header/DSPanelHeader.func.spec.js +24 -0
- package/ds-panel-header/DSPanelHeaderCO.js +17 -0
- package/ds-pills-v2/DSPillsV2CO.js +53 -1
- package/ds-pills-v2/pitfalls/DSPills.inputPill.func.spec.js +26 -0
- package/ds-pills-v2/pitfalls/DSPills.inputWithFormItemBlockURL.axe-core.func.spec.js +38 -0
- package/ds-pills-v2/pitfalls/DSPills.inputWithFormItemBlockURL.func.spec.js +72 -0
- package/ds-progress-indicator/DSProgressIndicator.axe-core.func.spec.js +8 -5
- package/ds-progress-indicator/DSProgressIndicator.func.spec.js +31 -4
- package/ds-progress-indicator/DSProgressIndicator.visual.spec.js +14 -6
- package/ds-progress-indicator/DSProgressIndicatorCO.js +87 -9
- package/ds-progress-indicator/aria-contract/DSProgressIndicator.aria-contract.func.spec.js +104 -0
- package/ds-progress-indicator/slots/DSProgressIndicator.slots.axe-core.func.spec.js +31 -0
- package/ds-progress-indicator/slots/DSProgressIndicator.slots.func.spec.js +87 -0
- package/ds-progress-indicator/slots/DSProgressIndicator.slots.visual.spec.js +27 -0
- package/ds-progress-indicator/variant/DSProgressIndicator.single-bar-variant.func.spec.js +44 -0
- package/ds-progress-indicator/variant/DSProgressIndicator.single-bar-variant.visual.spec.js +19 -0
- package/ds-ribbon/DSRibbonCO.js +21 -0
- package/ds-ribbon/keyboard-accessible-row/DSRibbon.keyboard-accessible-row.visual.spec.js +40 -0
- package/ds-ribbon/wrap-columns/DSRibbon.wrap-columns.visual.spec.js +18 -0
- package/ds-shuttle-v2/load-more/DSShuttleV2.load-more.keyboard.func.spec.js +46 -17
- package/ds-slider-v2/DSSliderV2.axe-core.func.spec.js +21 -0
- package/ds-slider-v2/DSSliderV2.visual.spec.js +19 -1
- package/ds-slider-v2/DSSliderV2CO.js +6 -1
- package/ds-slider-v2/has-error/DSSliderV2.has-error.visual.spec.js +44 -0
- package/ds-slider-v2/interaction-states/DSSliderV2.interaction-states.visual.spec.js +53 -0
- package/ds-virtuallist/DSVirtualList.visual.spec.js +4 -5
- package/ds-virtuallist/DSVirtualListCO.js +28 -9
- package/ds-virtuallist/basic/DSVirtualList.basic.axe-core.func.spec.js +28 -0
- package/ds-virtuallist/scroll-to-index/DSVirtualList.scroll-to-index.func.spec.js +45 -0
- package/package.json +149 -149
- package/paths.js +3 -49
- package/ds-leftnavigation/LeftNavigation.axe-core.func.spec.js +0 -172
- package/ds-mobile/Accordion/DSAccordion.visual.spec.js +0 -33
- package/ds-mobile/Accordion/DSAccordionCO.js +0 -37
- package/ds-mobile/CategoryBox/CategoryBox.visual.spec.js +0 -18
- package/ds-mobile/CategoryBox/CategoryBoxCO.js +0 -17
- package/ds-mobile/CollectionBox/CollectionBox.visual.spec.js +0 -16
- package/ds-mobile/CollectionBox/CollectionBoxCO.js +0 -15
- package/ds-mobile/GlobalHeader/DSGlobalHeader.visual.spec.js +0 -55
- package/ds-mobile/GlobalHeader/DSGlobalHeaderCO.js +0 -36
- package/ds-mobile/GroupBox/GroupBox.visual.spec.js +0 -15
- package/ds-mobile/GroupBox/GroupBoxCO.js +0 -15
- package/ds-mobile/InfiniteLoader/InfiniteLoader.func.spec.js +0 -90
- package/ds-mobile/InfiniteLoader/InfiniteLoaderCO.js +0 -29
- package/ds-mobile/MobileActionToolbar/MobileActionToolbar.visual.spec.js +0 -39
- package/ds-mobile/MobileActionToolbar/MobileActionToolbarCO.js +0 -19
- package/ds-mobile/MobileBanner/MobileBanner.visual.spec.js +0 -23
- package/ds-mobile/MobileBanner/MobileBannerCO.js +0 -23
- package/ds-mobile/MobileCard/Card.func.spec.js +0 -38
- package/ds-mobile/MobileCard/Card.visual.spec.js +0 -103
- package/ds-mobile/MobileCard/MobileCardCO.js +0 -42
- package/ds-mobile/MobileContextMenu/MobileContextMenu.func.spec.js +0 -88
- package/ds-mobile/MobileContextMenu/MobileContextMenu.visual.spec.js +0 -31
- package/ds-mobile/MobileContextMenu/MobileContextMenuCO.js +0 -72
- package/ds-mobile/MobileDatePicker/MobileDatePicker.func.spec.js +0 -15
- package/ds-mobile/MobileDatePicker/MobileDatePicker.visual.spec.js +0 -15
- package/ds-mobile/MobileDatePicker/MobileDatePickerCO.js +0 -35
- package/ds-mobile/MobileDropdownMenu/MobileDropdownMenu.func.spec.js +0 -38
- package/ds-mobile/MobileDropdownMenu/MobileDropdownMenu.visual.spec.js +0 -16
- package/ds-mobile/MobileDropdownMenu/MobileDropdownMenuCO.js +0 -37
- package/ds-mobile/MobileEmptyState/MobileEmptyState.visual.spec.js +0 -15
- package/ds-mobile/MobileEmptyState/MobileEmptyStateCO.js +0 -14
- package/ds-mobile/MobileFilterbar/MobileFilterbar.visual.spec.js +0 -39
- package/ds-mobile/MobileFilterbar/MobileFilterbarCO.js +0 -19
- package/ds-mobile/MobileFooter/MobileFooter.func.spec.js +0 -26
- package/ds-mobile/MobileFooter/MobileFooter.visual.spec.js +0 -51
- package/ds-mobile/MobileFooter/MobileFooterCO.js +0 -27
- package/ds-mobile/MobileListItem/MobileListItem.visual.spec.js +0 -56
- package/ds-mobile/MobileListItem/MobileListItemCO.js +0 -19
- package/ds-mobile/MobileLoadingPage/MobileLoadingPage.visual.spec.js +0 -37
- package/ds-mobile/MobileLoadingPage/MobileLoadingPageCO.js +0 -23
- package/ds-mobile/MobilePageHeader/MobilePageHeader.func.spec.js +0 -22
- package/ds-mobile/MobilePageHeader/MobilePageHeader.visual.spec.js +0 -135
- package/ds-mobile/MobilePageHeader/MobilePageHeaderCO.js +0 -67
- package/ds-mobile/MobileSelectList/MobileSelectList.visual.spec.js +0 -56
- package/ds-mobile/MobileSelectList/MobileSelectListCO.js +0 -21
- package/ds-mobile/MobileSeparator/MobileSeparator.visual.spec.js +0 -28
- package/ds-mobile/MobileSeparator/MobileSeparatorCO.js +0 -17
- package/ds-mobile/MobileTimePicker/MobileTimePickerCO.js +0 -41
- package/ds-mobile/Modal/MobileModal.visual.spec.js +0 -56
- package/ds-mobile/Modal/MobileModalCO.js +0 -28
- package/ds-mobile/PageFilter/PageFilter.visual.spec.js +0 -46
- package/ds-mobile/PageFilter/PageFilterCO.js +0 -19
- package/ds-mobile/PageForm/PageForm.visual.spec.js +0 -14
- package/ds-mobile/PageForm/PageFormCO.js +0 -11
- package/ds-mobile/PageList/PageList.visual.spec.js +0 -31
- package/ds-mobile/PageList/PageListCO.js +0 -19
- package/ds-mobile/PageSummary/PageSummary.visual.spec.js +0 -20
- package/ds-mobile/PageSummary/PageSummaryCO.js +0 -11
- package/ds-mobile/SwipeToRefresh/SwipeToRefresh.func.spec.js +0 -26
- package/ds-mobile/SwipeToRefresh/SwipeToRefreshCO.js +0 -20
- package/ds-mobile/Tabs/MobileTabs.visual.spec.js +0 -91
- package/ds-mobile/Tabs/TabsCO.js +0 -37
- package/ds-mobile/Tooltip/MobileTooltip.func.spec.js +0 -17
- package/ds-mobile/Tooltip/MobileTooltip.visual.spec.js +0 -16
- package/ds-mobile/Tooltip/TooltipCO.js +0 -23
- package/ds-mobile/helpers.js +0 -7
package/ds-banner/DSBannerCO.js
CHANGED
|
@@ -2,6 +2,12 @@ import { PATH_E2E_BANNER } from '../paths';
|
|
|
2
2
|
import { PageObject, Urlbuilder } from '../helpers';
|
|
3
3
|
|
|
4
4
|
export default class DSBannerCO extends PageObject {
|
|
5
|
+
// label/body rendered by the AriaLive* and RoleAlert E2E stories
|
|
6
|
+
static ANNOUNCEMENT_TITLE = 'Information: Read-only mode';
|
|
7
|
+
|
|
8
|
+
static ANNOUNCEMENT_BODY =
|
|
9
|
+
'You are viewing this page in read-only mode. Editing is currently disabled for your role.';
|
|
10
|
+
|
|
5
11
|
static basicURL = new Urlbuilder(PATH_E2E_BANNER, 'basic-test');
|
|
6
12
|
|
|
7
13
|
static infoURL = new Urlbuilder(PATH_E2E_BANNER, 'info-test');
|
|
@@ -36,6 +42,32 @@ export default class DSBannerCO extends PageObject {
|
|
|
36
42
|
|
|
37
43
|
static roleRegionTest = new Urlbuilder(PATH_E2E_BANNER, 'role-region-test');
|
|
38
44
|
|
|
45
|
+
static roleRegionNoAnnouncementTest = new Urlbuilder(PATH_E2E_BANNER, 'role-region-no-announcement-test');
|
|
46
|
+
|
|
47
|
+
static regionAccessibleNameTest = new Urlbuilder(PATH_E2E_BANNER, 'region-accessible-name-test');
|
|
48
|
+
|
|
49
|
+
static bannerIdsTest = new Urlbuilder(PATH_E2E_BANNER, 'banner-ids-test');
|
|
50
|
+
|
|
51
|
+
static liveRegionLangDirTest = new Urlbuilder(PATH_E2E_BANNER, 'live-region-lang-dir-test');
|
|
52
|
+
|
|
53
|
+
// each banner in RegionAccessibleNameTest is wrapped in a div with a per-case data-testid
|
|
54
|
+
static async getRegionByCase(caseTestId) {
|
|
55
|
+
return $(`[data-testid="${caseTestId}"] [role="region"]`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static async getRegionNameAttributes(caseTestId) {
|
|
59
|
+
const region = await this.getRegionByCase(caseTestId);
|
|
60
|
+
return {
|
|
61
|
+
ariaLabel: await region.getAttribute('aria-label'),
|
|
62
|
+
ariaLabelledby: await region.getAttribute('aria-labelledby'),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// located by its parent slot, not by tag (the title tag is changing, PUI-19231)
|
|
67
|
+
static async getRegionTitleByCase(caseTestId) {
|
|
68
|
+
return $(`[data-testid="${caseTestId}"] [data-dimsum-parent-slot="dsBannerTitle"]`);
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
static async getButton() {
|
|
40
72
|
return $('[data-testid="ds-button"]');
|
|
41
73
|
}
|
|
@@ -43,6 +75,8 @@ export default class DSBannerCO extends PageObject {
|
|
|
43
75
|
static async openBanner() {
|
|
44
76
|
const button = await this.getButton();
|
|
45
77
|
await button.click();
|
|
78
|
+
// the banner slides down for 500 ms, the callers (visual snapshots included) expect it settled
|
|
79
|
+
await this.waitForSlideToEnd();
|
|
46
80
|
}
|
|
47
81
|
|
|
48
82
|
static async closeBanner() {
|
|
@@ -50,6 +84,73 @@ export default class DSBannerCO extends PageObject {
|
|
|
50
84
|
await closeBtn.click();
|
|
51
85
|
}
|
|
52
86
|
|
|
87
|
+
static async getPushedContent() {
|
|
88
|
+
return $('[data-testid="banner-pushed-content"]');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static async getPushedContentTop() {
|
|
92
|
+
return browser.execute(
|
|
93
|
+
() => document.querySelector('[data-testid="banner-pushed-content"]').getBoundingClientRect().top,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// resolves once no banner has a running animation/transition (the slide down) or is in the DOM
|
|
98
|
+
static async waitForSlideToEnd() {
|
|
99
|
+
await browser.waitUntil(
|
|
100
|
+
async () =>
|
|
101
|
+
browser.execute(() =>
|
|
102
|
+
Array.from(document.querySelectorAll('[data-testid="ds-banner-container"]')).every(
|
|
103
|
+
(container) => container.getAnimations().length === 0,
|
|
104
|
+
),
|
|
105
|
+
),
|
|
106
|
+
{ timeoutMsg: 'the banner slide did not end' },
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Samples, on every animation frame and from the page (so the webdriver latency does not matter), the height of the
|
|
111
|
+
// banner container and the top of the content pushed by it. The click is triggered from the page right after the
|
|
112
|
+
// first sample, so the very first frames after it are recorded. action: 'open' | 'close'.
|
|
113
|
+
static async sampleSlide(action, durationMs = 1200) {
|
|
114
|
+
await browser.execute(
|
|
115
|
+
(actionToRun, duration) => {
|
|
116
|
+
const samples = [];
|
|
117
|
+
window.bannerSlideSampler = { samples, done: false };
|
|
118
|
+
const startedAt = performance.now();
|
|
119
|
+
const sample = () => {
|
|
120
|
+
const container = document.querySelector('[data-testid="ds-banner-container"]');
|
|
121
|
+
const pushed = document.querySelector('[data-testid="banner-pushed-content"]');
|
|
122
|
+
samples.push({
|
|
123
|
+
t: Math.round(performance.now() - startedAt),
|
|
124
|
+
height: container ? container.getBoundingClientRect().height : null,
|
|
125
|
+
pushedTop: pushed.getBoundingClientRect().top,
|
|
126
|
+
inert: container ? container.hasAttribute('inert') : null,
|
|
127
|
+
ariaHidden: container ? container.getAttribute('aria-hidden') : null,
|
|
128
|
+
focusInside: container ? container.contains(document.activeElement) : false,
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
sample();
|
|
132
|
+
if (actionToRun === 'open') document.querySelector('[data-testid="ds-button"]').click();
|
|
133
|
+
else {
|
|
134
|
+
const closeButton = document.querySelector('[data-testid="ds-banner-close-button"]');
|
|
135
|
+
closeButton.focus();
|
|
136
|
+
closeButton.click();
|
|
137
|
+
}
|
|
138
|
+
const tick = () => {
|
|
139
|
+
sample();
|
|
140
|
+
if (performance.now() - startedAt < duration) requestAnimationFrame(tick);
|
|
141
|
+
else window.bannerSlideSampler.done = true;
|
|
142
|
+
};
|
|
143
|
+
requestAnimationFrame(tick);
|
|
144
|
+
},
|
|
145
|
+
action,
|
|
146
|
+
durationMs,
|
|
147
|
+
);
|
|
148
|
+
await browser.waitUntil(async () => browser.execute(() => window.bannerSlideSampler.done), {
|
|
149
|
+
timeoutMsg: 'the slide sampler did not finish',
|
|
150
|
+
});
|
|
151
|
+
return browser.execute(() => window.bannerSlideSampler.samples);
|
|
152
|
+
}
|
|
153
|
+
|
|
53
154
|
static async getCloseButton() {
|
|
54
155
|
return $('[data-testid="ds-banner-close-button"]');
|
|
55
156
|
}
|
|
@@ -75,7 +176,7 @@ export default class DSBannerCO extends PageObject {
|
|
|
75
176
|
}
|
|
76
177
|
|
|
77
178
|
static async getActionLinkSlotByIndex(index = 0) {
|
|
78
|
-
return $$('[data-dimsum-slot="dsBannerActionLink"]')[index];
|
|
179
|
+
return $$('[data-dimsum-parent-slot="dsBannerActionLink"]')[index];
|
|
79
180
|
}
|
|
80
181
|
|
|
81
182
|
static async getTitleSlotByIndex(index = 0) {
|
|
@@ -90,10 +191,44 @@ export default class DSBannerCO extends PageObject {
|
|
|
90
191
|
return $$('[data-dimsum-slot="dsButtonRoot"]')[index];
|
|
91
192
|
}
|
|
92
193
|
|
|
194
|
+
static async getCloseButtonSlotByIndex(index = 0) {
|
|
195
|
+
return $$('[data-dimsum-parent-slot="dsBannerCloseButton"]')[index];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static async getLiveRegionPortal() {
|
|
199
|
+
return $('[data-testid="ds-banner-live-region-portal"]');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// the live region is visually hidden, so read textContent instead of the visible text
|
|
203
|
+
static async getLiveRegionText() {
|
|
204
|
+
const liveRegion = await this.getLiveRegionPortal();
|
|
205
|
+
return ((await liveRegion.getProperty('textContent')) || '').trim();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static async waitForLiveRegionText(expected) {
|
|
209
|
+
await browser.waitUntil(async () => (await this.getLiveRegionText()).includes(expected), {
|
|
210
|
+
timeoutMsg: `live region never contained "${expected}"`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
static async waitForLiveRegionCleared() {
|
|
215
|
+
await browser.waitUntil(async () => (await this.getLiveRegionText()) === '', {
|
|
216
|
+
timeoutMsg: 'live region was not cleared after closing the banner',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static async getActiveElementTestId() {
|
|
221
|
+
return browser.execute(() => document.activeElement?.getAttribute('data-testid') ?? null);
|
|
222
|
+
}
|
|
223
|
+
|
|
93
224
|
static async getContainerSlotByIndex(index = 0) {
|
|
94
225
|
return $$('[data-dimsum-slot="dsBannerContainer"]')[index];
|
|
95
226
|
}
|
|
96
227
|
|
|
228
|
+
static async getBodySlotByIndex(index = 0) {
|
|
229
|
+
return $$('[data-dimsum-slot="dsBannerBody"]')[index];
|
|
230
|
+
}
|
|
231
|
+
|
|
97
232
|
static async getLayoutSlotByIndex(index = 0) {
|
|
98
233
|
return $$('[data-dimsum-slot="dsBannerLayout"]')[index];
|
|
99
234
|
}
|
|
@@ -110,8 +245,58 @@ export default class DSBannerCO extends PageObject {
|
|
|
110
245
|
return $$('[data-dimsum-slot="dsBannerLiveRegionPortal"]')[index];
|
|
111
246
|
}
|
|
112
247
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
248
|
+
static async getTitle() {
|
|
249
|
+
return $('[data-testid="ds-banner-title"]');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// headings (native or by role) rendered inside the banners, the page outside them is not the banner's business
|
|
253
|
+
static async getHeadingsCountInBanners() {
|
|
254
|
+
return browser.execute(
|
|
255
|
+
() =>
|
|
256
|
+
document.querySelectorAll('[data-testid="ds-banner-container"] :is(h1, h2, h3, h4, h5, h6, [role="heading"])')
|
|
257
|
+
.length,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static async getLiveRegionPortalByIndex(index = 0) {
|
|
262
|
+
return $$('[data-testid="ds-banner-live-region-portal"]')[index];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// per banner (in page order): the ids of its parts and whether <base>-live-region is its live region portal
|
|
266
|
+
static async getBannerIds() {
|
|
267
|
+
return browser.execute(() =>
|
|
268
|
+
Array.from(document.querySelectorAll('[data-testid="ds-banner"]')).map((banner) => ({
|
|
269
|
+
base: banner.id,
|
|
270
|
+
title: banner.querySelector('[data-testid="ds-banner-title"]')?.id ?? null,
|
|
271
|
+
body: banner.querySelector('[data-dimsum-parent-slot="dsBannerSubtitle"]')?.id ?? null,
|
|
272
|
+
liveRegionTestId: document.getElementById(`${banner.id}-live-region`)?.getAttribute('data-testid') ?? null,
|
|
273
|
+
})),
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// every id rendered by the banners (parts and live region portals), so duplicates among them can be detected
|
|
278
|
+
static async getAllBannerIds() {
|
|
279
|
+
return browser.execute(() => {
|
|
280
|
+
const selectors = [
|
|
281
|
+
'[data-testid="ds-banner-container"][id]',
|
|
282
|
+
'[data-testid="ds-banner-container"] [id]',
|
|
283
|
+
'[data-testid="ds-banner-live-region-portal"]',
|
|
284
|
+
];
|
|
285
|
+
return Array.from(document.querySelectorAll(selectors.join(', '))).map((element) => element.id);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// what the action link of the banner at index points to with aria-describedby
|
|
290
|
+
static async getActionLinkDescription(index = 0) {
|
|
291
|
+
return browser.execute((position) => {
|
|
292
|
+
const link = document.querySelectorAll('[data-testid="ds-banner-action-link"]')[position];
|
|
293
|
+
const describedBy = link.getAttribute('aria-describedby');
|
|
294
|
+
const target = document.getElementById(describedBy);
|
|
295
|
+
return {
|
|
296
|
+
describedBy,
|
|
297
|
+
isInsideOwnBanner: Boolean(target && link.closest('[data-testid="ds-banner"]').contains(target)),
|
|
298
|
+
text: target ? target.textContent : null,
|
|
299
|
+
};
|
|
300
|
+
}, index);
|
|
116
301
|
}
|
|
117
302
|
}
|
|
@@ -6,31 +6,76 @@ if (
|
|
|
6
6
|
browser.capabilities.browserName === 'chrome') ||
|
|
7
7
|
browser.capabilities.browserName === 'Chrome'
|
|
8
8
|
) {
|
|
9
|
+
// Announcement behaviour also covers PUI-17840 (banner announcement improvement)
|
|
9
10
|
describe('PUI-17537 - Banner - Aria Assertive -Func', () => {
|
|
10
11
|
before('loading page', async () => {
|
|
11
12
|
const errorOnGo = await DSBannerCO.ariaLiveAssertiveTest.go();
|
|
12
13
|
if (errorOnGo) throw errorOnGo;
|
|
13
14
|
});
|
|
14
|
-
it('01: should
|
|
15
|
+
it('01: should render an empty assertive live region before the banner opens', async () => {
|
|
16
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
17
|
+
await expect(liveRegion).toExist();
|
|
18
|
+
await expect(liveRegion).toHaveAttribute('aria-live', 'assertive');
|
|
19
|
+
await expect(liveRegion).toHaveAttribute('aria-atomic', 'true');
|
|
20
|
+
await expect(await DSBannerCO.getLiveRegionText()).toBe('');
|
|
21
|
+
});
|
|
22
|
+
it('02: should have aria-live="assertive" attribute on banner after trigger', async () => {
|
|
15
23
|
const triggerButton = await DSBannerCO.getButton();
|
|
16
24
|
await triggerButton.click();
|
|
17
25
|
const banner = await DSBannerCO.getBannerLiveRegionPortalSlotByIndex();
|
|
18
26
|
await banner.waitForDisplayed();
|
|
19
27
|
await expect(banner).toHaveAttribute('aria-live', 'assertive');
|
|
20
28
|
});
|
|
29
|
+
it('03: should announce title and body together without moving focus', async () => {
|
|
30
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
31
|
+
await DSBannerCO.waitForLiveRegionText(DSBannerCO.ANNOUNCEMENT_TITLE);
|
|
32
|
+
await expect(await DSBannerCO.getLiveRegionText()).toContain(DSBannerCO.ANNOUNCEMENT_BODY);
|
|
33
|
+
await expect(await liveRegion.$$('button, a').length).toBe(0);
|
|
34
|
+
const banner = await DSBannerCO.getBanner();
|
|
35
|
+
await expect(banner).not.toHaveAttribute('role');
|
|
36
|
+
await expect(await DSBannerCO.getActiveElementTestId()).toBe('ds-button');
|
|
37
|
+
});
|
|
38
|
+
it('04: should clear the live region on close and fill it again on reopen', async () => {
|
|
39
|
+
await DSBannerCO.closeBanner();
|
|
40
|
+
await DSBannerCO.waitForLiveRegionCleared();
|
|
41
|
+
await DSBannerCO.openBanner();
|
|
42
|
+
await DSBannerCO.waitForLiveRegionText(DSBannerCO.ANNOUNCEMENT_TITLE);
|
|
43
|
+
});
|
|
21
44
|
});
|
|
22
45
|
describe('PUI-17538 - Banner - Aria Polite -Func', () => {
|
|
23
46
|
before('loading page', async () => {
|
|
24
47
|
const errorOnGo = await DSBannerCO.ariaLivePoliteTest.go();
|
|
25
48
|
if (errorOnGo) throw errorOnGo;
|
|
26
49
|
});
|
|
27
|
-
it('01: should
|
|
50
|
+
it('01: should render an empty polite live region before the banner opens', async () => {
|
|
51
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
52
|
+
await expect(liveRegion).toExist();
|
|
53
|
+
await expect(liveRegion).toHaveAttribute('aria-live', 'polite');
|
|
54
|
+
await expect(liveRegion).toHaveAttribute('aria-atomic', 'true');
|
|
55
|
+
await expect(await DSBannerCO.getLiveRegionText()).toBe('');
|
|
56
|
+
});
|
|
57
|
+
it('02: should have aria-live="polite" attribute on banner after trigger', async () => {
|
|
28
58
|
const triggerButton = await DSBannerCO.getButton();
|
|
29
59
|
await triggerButton.click();
|
|
30
60
|
const banner = await DSBannerCO.getBannerLiveRegionPortalSlotByIndex();
|
|
31
61
|
await banner.waitForDisplayed();
|
|
32
62
|
await expect(banner).toHaveAttribute('aria-live', 'polite');
|
|
33
63
|
});
|
|
64
|
+
it('03: should announce title and body together without moving focus', async () => {
|
|
65
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
66
|
+
await DSBannerCO.waitForLiveRegionText(DSBannerCO.ANNOUNCEMENT_TITLE);
|
|
67
|
+
await expect(await DSBannerCO.getLiveRegionText()).toContain(DSBannerCO.ANNOUNCEMENT_BODY);
|
|
68
|
+
await expect(await liveRegion.$$('button, a').length).toBe(0);
|
|
69
|
+
const banner = await DSBannerCO.getBanner();
|
|
70
|
+
await expect(banner).not.toHaveAttribute('role');
|
|
71
|
+
await expect(await DSBannerCO.getActiveElementTestId()).toBe('ds-button');
|
|
72
|
+
});
|
|
73
|
+
it('04: should clear the live region on close and fill it again on reopen', async () => {
|
|
74
|
+
await DSBannerCO.closeBanner();
|
|
75
|
+
await DSBannerCO.waitForLiveRegionCleared();
|
|
76
|
+
await DSBannerCO.openBanner();
|
|
77
|
+
await DSBannerCO.waitForLiveRegionText(DSBannerCO.ANNOUNCEMENT_TITLE);
|
|
78
|
+
});
|
|
34
79
|
});
|
|
35
80
|
describe('PUI-17539 - Banner - Role Alert -Func', () => {
|
|
36
81
|
before('loading page', async () => {
|
|
@@ -44,6 +89,15 @@ if (
|
|
|
44
89
|
await banner.waitForDisplayed();
|
|
45
90
|
await expect(banner).toHaveAttribute('role', 'alert');
|
|
46
91
|
});
|
|
92
|
+
it('02: should announce title and body in the alert without moving focus', async () => {
|
|
93
|
+
const banner = await DSBannerCO.getBanner();
|
|
94
|
+
await expect(banner).toHaveText(expect.stringContaining(DSBannerCO.ANNOUNCEMENT_TITLE));
|
|
95
|
+
await expect(banner).toHaveText(expect.stringContaining(DSBannerCO.ANNOUNCEMENT_BODY));
|
|
96
|
+
await expect(await banner.$$('button, a').length).toBe(0);
|
|
97
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
98
|
+
await expect(liveRegion).not.toExist();
|
|
99
|
+
await expect(await DSBannerCO.getActiveElementTestId()).toBe('ds-button');
|
|
100
|
+
});
|
|
47
101
|
});
|
|
48
102
|
describe('PUI-17540 - Banner - Role Region and Alert -Func', () => {
|
|
49
103
|
before('loading page', async () => {
|
|
@@ -60,4 +114,61 @@ if (
|
|
|
60
114
|
await expect(banner).toHaveAttribute('role', 'alert');
|
|
61
115
|
});
|
|
62
116
|
});
|
|
117
|
+
// Documented action-link setup (isPageNotice + withLiveRegionAnnouncement="none"), PUI-17840
|
|
118
|
+
describe('PUI-19264 - DSBanner:: region without live announcement - Func', () => {
|
|
119
|
+
before('loading page', async () => {
|
|
120
|
+
const errorOnGo = await DSBannerCO.roleRegionNoAnnouncementTest.go();
|
|
121
|
+
if (errorOnGo) throw errorOnGo;
|
|
122
|
+
});
|
|
123
|
+
it('01: should render a page region that is not announced automatically', async () => {
|
|
124
|
+
const bannerContainer = await DSBannerCO.getBannerContainer();
|
|
125
|
+
await bannerContainer.waitForDisplayed();
|
|
126
|
+
await expect(bannerContainer).toHaveAttribute('role', 'region');
|
|
127
|
+
await expect(await $$('[role="alert"]').length).toBe(0);
|
|
128
|
+
const liveRegion = await DSBannerCO.getLiveRegionPortal();
|
|
129
|
+
await expect(liveRegion).not.toExist();
|
|
130
|
+
const actionLink = await DSBannerCO.getActionLink();
|
|
131
|
+
await expect(actionLink).toHaveAttribute('href');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// Tests for the fix introduced in PUI-19088 (isPageNotice region had no accessible name)
|
|
135
|
+
describe('PUI-19265 - DSBanner:: page notice region accessible name - Func', () => {
|
|
136
|
+
before('loading page', async () => {
|
|
137
|
+
const errorOnGo = await DSBannerCO.regionAccessibleNameTest.go();
|
|
138
|
+
if (errorOnGo) throw errorOnGo;
|
|
139
|
+
});
|
|
140
|
+
it('01: should name each page notice region from its title, its label or the consumer name', async () => {
|
|
141
|
+
const defaultRegion = await DSBannerCO.getRegionByCase('region-default-name');
|
|
142
|
+
await defaultRegion.waitForDisplayed();
|
|
143
|
+
const defaultTitle = await DSBannerCO.getRegionTitleByCase('region-default-name');
|
|
144
|
+
const defaultTitleId = await defaultTitle.getAttribute('id');
|
|
145
|
+
await expect(defaultTitleId).toBeTruthy();
|
|
146
|
+
await expect(defaultTitle).toHaveText('Default name from title');
|
|
147
|
+
await expect(await DSBannerCO.getRegionNameAttributes('region-default-name')).toEqual({
|
|
148
|
+
ariaLabel: null,
|
|
149
|
+
ariaLabelledby: defaultTitleId,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const secondTitle = await DSBannerCO.getRegionTitleByCase('region-second-default-name');
|
|
153
|
+
const secondTitleId = await secondTitle.getAttribute('id');
|
|
154
|
+
await expect(secondTitleId).not.toBe(defaultTitleId);
|
|
155
|
+
await expect(await DSBannerCO.getRegionNameAttributes('region-second-default-name')).toEqual({
|
|
156
|
+
ariaLabel: null,
|
|
157
|
+
ariaLabelledby: secondTitleId,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
await expect(await DSBannerCO.getRegionNameAttributes('region-custom-body')).toEqual({
|
|
161
|
+
ariaLabel: 'Custom body label',
|
|
162
|
+
ariaLabelledby: null,
|
|
163
|
+
});
|
|
164
|
+
await expect(await DSBannerCO.getRegionNameAttributes('region-slot-name')).toEqual({
|
|
165
|
+
ariaLabel: 'Name from container slot',
|
|
166
|
+
ariaLabelledby: null,
|
|
167
|
+
});
|
|
168
|
+
await expect(await DSBannerCO.getRegionNameAttributes('region-container-props-name')).toEqual({
|
|
169
|
+
ariaLabel: 'Name from containerProps',
|
|
170
|
+
ariaLabelledby: null,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
63
174
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import DSBannerCO from '../DSBannerCO';
|
|
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
|
+
// Tests for the fix introduced in PUI-19089 (the body had the hardcoded id "ds-banner-body", repeated per banner)
|
|
10
|
+
describe('PUI-19271 - DSBanner:: per-instance ids and bannerId references - Func', () => {
|
|
11
|
+
const GENERATED_ONE = 0;
|
|
12
|
+
const GENERATED_TWO = 1;
|
|
13
|
+
const SAVED = 2;
|
|
14
|
+
const MAINTENANCE = 3;
|
|
15
|
+
|
|
16
|
+
let bannerIds;
|
|
17
|
+
|
|
18
|
+
before('loading page', async () => {
|
|
19
|
+
const errorOnGo = await DSBannerCO.bannerIdsTest.go();
|
|
20
|
+
if (errorOnGo) throw errorOnGo;
|
|
21
|
+
bannerIds = await DSBannerCO.getBannerIds();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('01: should render unique ids derived from one base for banners without bannerId', async () => {
|
|
25
|
+
const allIds = await DSBannerCO.getAllBannerIds();
|
|
26
|
+
await expect(allIds.length).toBe(new Set(allIds).size);
|
|
27
|
+
await expect(allIds).not.toContain('ds-banner-body');
|
|
28
|
+
|
|
29
|
+
[GENERATED_ONE, GENERATED_TWO].forEach((index) => {
|
|
30
|
+
const { base, title, body, liveRegionTestId } = bannerIds[index];
|
|
31
|
+
expect(base).toMatch(/^[A-Za-z]/);
|
|
32
|
+
expect(title).toBe(`${base}-title`);
|
|
33
|
+
expect(body).toBe(`${base}-body`);
|
|
34
|
+
expect(liveRegionTestId).toBe('ds-banner-live-region-portal');
|
|
35
|
+
});
|
|
36
|
+
await expect(bannerIds[GENERATED_ONE].base).not.toBe(bannerIds[GENERATED_TWO].base);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('02: should derive every id from the bannerId set by the consumer', async () => {
|
|
40
|
+
await expect(bannerIds[SAVED]).toEqual({
|
|
41
|
+
base: 'saved-banner',
|
|
42
|
+
title: 'saved-banner-title',
|
|
43
|
+
body: 'saved-banner-body',
|
|
44
|
+
liveRegionTestId: 'ds-banner-live-region-portal',
|
|
45
|
+
});
|
|
46
|
+
await expect(bannerIds[MAINTENANCE]).toEqual({
|
|
47
|
+
base: 'maintenance-banner',
|
|
48
|
+
title: 'maintenance-banner-title',
|
|
49
|
+
body: 'maintenance-banner-body',
|
|
50
|
+
liveRegionTestId: 'ds-banner-live-region-portal',
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('03: should describe each action link with the body of its own banner', async () => {
|
|
55
|
+
const savedDescription = await DSBannerCO.getActionLinkDescription(0);
|
|
56
|
+
await expect(savedDescription.describedBy).toBe('saved-banner-body');
|
|
57
|
+
await expect(savedDescription.isInsideOwnBanner).toBe(true);
|
|
58
|
+
await expect(savedDescription.text).toContain('Your settings were saved successfully.');
|
|
59
|
+
|
|
60
|
+
const maintenanceDescription = await DSBannerCO.getActionLinkDescription(1);
|
|
61
|
+
await expect(maintenanceDescription.describedBy).toBe('maintenance-banner-body');
|
|
62
|
+
await expect(maintenanceDescription.isInsideOwnBanner).toBe(true);
|
|
63
|
+
await expect(maintenanceDescription.text).toContain('A maintenance window starts tonight at 10 PM.');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import DSBannerCO from '../DSBannerCO';
|
|
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
|
+
// Tests for the fix introduced in PUI-19090 (the live region portal did not carry the lang and dir of the banner)
|
|
10
|
+
describe('PUI-19272 - DSBanner:: live region lang and dir - Func', () => {
|
|
11
|
+
const POLITE = 0;
|
|
12
|
+
const ASSERTIVE = 1;
|
|
13
|
+
const WITHOUT_LANG_DIR = 2;
|
|
14
|
+
|
|
15
|
+
before('loading page', async () => {
|
|
16
|
+
const errorOnGo = await DSBannerCO.liveRegionLangDirTest.go();
|
|
17
|
+
if (errorOnGo) throw errorOnGo;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('01: should carry the lang and dir of the banner in the polite and assertive live regions', async () => {
|
|
21
|
+
const politePortal = await DSBannerCO.getLiveRegionPortalByIndex(POLITE);
|
|
22
|
+
await expect(politePortal).toHaveAttribute('lang', 'fr');
|
|
23
|
+
await expect(politePortal).toHaveAttribute('dir', 'rtl');
|
|
24
|
+
|
|
25
|
+
const assertivePortal = await DSBannerCO.getLiveRegionPortalByIndex(ASSERTIVE);
|
|
26
|
+
await expect(assertivePortal).toHaveAttribute('lang', 'es');
|
|
27
|
+
await expect(assertivePortal).toHaveAttribute('dir', 'ltr');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('02: should not render lang or dir in the live region of a banner that does not set them', async () => {
|
|
31
|
+
const portal = await DSBannerCO.getLiveRegionPortalByIndex(WITHOUT_LANG_DIR);
|
|
32
|
+
await expect(portal).not.toHaveAttribute('lang');
|
|
33
|
+
await expect(portal).not.toHaveAttribute('dir');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('03: should keep lang and dir in the live regions after the banners are closed', async () => {
|
|
37
|
+
const toggleButton = await DSBannerCO.getButton();
|
|
38
|
+
await toggleButton.click();
|
|
39
|
+
await DSBannerCO.waitForLiveRegionCleared();
|
|
40
|
+
|
|
41
|
+
const politePortal = await DSBannerCO.getLiveRegionPortalByIndex(POLITE);
|
|
42
|
+
await expect(politePortal).toHaveAttribute('lang', 'fr');
|
|
43
|
+
await expect(politePortal).toHaveAttribute('dir', 'rtl');
|
|
44
|
+
|
|
45
|
+
const assertivePortal = await DSBannerCO.getLiveRegionPortalByIndex(ASSERTIVE);
|
|
46
|
+
await expect(assertivePortal).toHaveAttribute('lang', 'es');
|
|
47
|
+
await expect(assertivePortal).toHaveAttribute('dir', 'ltr');
|
|
48
|
+
|
|
49
|
+
const portalWithoutLangDir = await DSBannerCO.getLiveRegionPortalByIndex(WITHOUT_LANG_DIR);
|
|
50
|
+
await expect(portalWithoutLangDir).not.toHaveAttribute('lang');
|
|
51
|
+
await expect(portalWithoutLangDir).not.toHaveAttribute('dir');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import DSBannerCO from '../DSBannerCO';
|
|
2
|
+
|
|
3
|
+
// the samples come from the page (requestAnimationFrame), so these tolerances only absorb the machine speed
|
|
4
|
+
const MOTION_MS = 500;
|
|
5
|
+
const MIN_END_MS = MOTION_MS * 0.7;
|
|
6
|
+
const MAX_END_MS = MOTION_MS * 2;
|
|
7
|
+
const MIN_INTERMEDIATE_FRAMES = 5;
|
|
8
|
+
const PX_TOLERANCE = 1;
|
|
9
|
+
|
|
10
|
+
const isIntermediate = (height, fullHeight) => height > PX_TOLERANCE && height < fullHeight - PX_TOLERANCE;
|
|
11
|
+
const heights = (samples) => samples.map(({ height }) => height).filter((height) => height !== null);
|
|
12
|
+
// the frames of the motion: from the first one that is clearly collapsed. Some engines report, in the sampler's very
|
|
13
|
+
// first frame, the size of a layout flushed before their first rendering update (the banner never paints like that)
|
|
14
|
+
const getMotionFrames = (samples, fullHeight) => {
|
|
15
|
+
const start = samples.findIndex(({ height }) => height !== null && height < fullHeight * 0.5);
|
|
16
|
+
return start === -1 ? [] : samples.slice(start);
|
|
17
|
+
};
|
|
18
|
+
const isMonotonic = (values, direction) =>
|
|
19
|
+
values.every((value, index) => index === 0 || (value - values[index - 1]) * direction >= -PX_TOLERANCE);
|
|
20
|
+
|
|
21
|
+
// Banner spec v2, "Motion and Animation": the banner slides down (open) and up (close) in 500 ms, pushing the content
|
|
22
|
+
// below gradually. Tests for the fix introduced in PUI-19232 (the slide was not rendered).
|
|
23
|
+
if (!browser.capabilities['ice:options'].isPhone && !browser.capabilities['ice:options'].isTablet) {
|
|
24
|
+
describe('PUI-19269 - Banner:: open and close slide animation (500 ms) - Func', () => {
|
|
25
|
+
let openSamples;
|
|
26
|
+
let openFrames;
|
|
27
|
+
let closeSamples;
|
|
28
|
+
let closedPushedTop;
|
|
29
|
+
let fullHeight;
|
|
30
|
+
|
|
31
|
+
before('loading page', async () => {
|
|
32
|
+
const errorOnGo = await DSBannerCO.pushesContentURL.go();
|
|
33
|
+
if (errorOnGo) throw errorOnGo;
|
|
34
|
+
closedPushedTop = await DSBannerCO.getPushedContentTop();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('01: should grow the banner gradually from 0 to its full height when opening', async () => {
|
|
38
|
+
openSamples = await DSBannerCO.sampleSlide('open');
|
|
39
|
+
const withBanner = openSamples.filter(({ height }) => height !== null);
|
|
40
|
+
fullHeight = withBanner[withBanner.length - 1].height;
|
|
41
|
+
expect(fullHeight).toBeGreaterThan(50);
|
|
42
|
+
// not at full height from the start: there are frames in which the banner is (almost) collapsed
|
|
43
|
+
openFrames = getMotionFrames(openSamples, fullHeight);
|
|
44
|
+
expect(openFrames.length).toBeGreaterThan(0);
|
|
45
|
+
expect(openFrames[0].height).toBeLessThan(fullHeight * 0.25);
|
|
46
|
+
// several frames in between and never shrinking
|
|
47
|
+
expect(heights(openFrames).filter((height) => isIntermediate(height, fullHeight)).length).toBeGreaterThanOrEqual(
|
|
48
|
+
MIN_INTERMEDIATE_FRAMES,
|
|
49
|
+
);
|
|
50
|
+
expect(isMonotonic(heights(openFrames), 1)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('02: should take about 500 ms to reach the full height when opening', async () => {
|
|
54
|
+
const reached = openFrames.find(({ height }) => height >= fullHeight - PX_TOLERANCE);
|
|
55
|
+
expect(reached.t).toBeGreaterThanOrEqual(MIN_END_MS);
|
|
56
|
+
expect(reached.t).toBeLessThanOrEqual(MAX_END_MS);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('03: should push the content below gradually and in sync with the banner when opening', async () => {
|
|
60
|
+
const pushedTops = openFrames.map(({ pushedTop }) => pushedTop);
|
|
61
|
+
expect(isMonotonic(pushedTops, 1)).toBe(true);
|
|
62
|
+
expect(
|
|
63
|
+
pushedTops.filter((top) => isIntermediate(top - closedPushedTop, fullHeight)).length,
|
|
64
|
+
).toBeGreaterThanOrEqual(MIN_INTERMEDIATE_FRAMES);
|
|
65
|
+
openFrames.forEach(({ height, pushedTop }) => expect(pushedTop - closedPushedTop).toBeCloseTo(height, 0));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('04: should keep the banner in the document, closed for everyone, while it slides up', async () => {
|
|
69
|
+
closeSamples = await DSBannerCO.sampleSlide('close');
|
|
70
|
+
// not removed on the first frame
|
|
71
|
+
expect(closeSamples.filter(({ height }) => height !== null).length).toBeGreaterThan(MIN_INTERMEDIATE_FRAMES);
|
|
72
|
+
expect(closeSamples[1].height).toBeGreaterThan(fullHeight * 0.5);
|
|
73
|
+
// from the first rendered frame after the click: not exposed and not interactive
|
|
74
|
+
const sliding = closeSamples.filter(({ height, t }) => height !== null && t > 0);
|
|
75
|
+
sliding.forEach(({ inert, ariaHidden }) => {
|
|
76
|
+
expect(inert).toBe(true);
|
|
77
|
+
expect(ariaHidden).toBe('true');
|
|
78
|
+
});
|
|
79
|
+
// the close button had focus: once inert the focus is not inside the banner anymore
|
|
80
|
+
closeSamples
|
|
81
|
+
.filter(({ height, t }) => height !== null && t > 100)
|
|
82
|
+
.forEach(({ focusInside }) => expect(focusInside).toBe(false));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('05: should collapse gradually and be removed after about 500 ms when closing', async () => {
|
|
86
|
+
expect(isMonotonic(heights(closeSamples), -1)).toBe(true);
|
|
87
|
+
expect(
|
|
88
|
+
heights(closeSamples).filter((height) => isIntermediate(height, fullHeight)).length,
|
|
89
|
+
).toBeGreaterThanOrEqual(MIN_INTERMEDIATE_FRAMES);
|
|
90
|
+
const removed = closeSamples.find(({ height }) => height === null);
|
|
91
|
+
expect(removed.t).toBeGreaterThanOrEqual(MIN_END_MS);
|
|
92
|
+
expect(removed.t).toBeLessThanOrEqual(MAX_END_MS);
|
|
93
|
+
await expect(await DSBannerCO.getBannerContainer()).not.toExist();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('06: should move the content below back gradually when closing', async () => {
|
|
97
|
+
const pushedTops = closeSamples.map(({ pushedTop }) => pushedTop);
|
|
98
|
+
expect(isMonotonic(pushedTops, -1)).toBe(true);
|
|
99
|
+
expect(
|
|
100
|
+
pushedTops.filter((top) => isIntermediate(top - closedPushedTop, fullHeight)).length,
|
|
101
|
+
).toBeGreaterThanOrEqual(MIN_INTERMEDIATE_FRAMES);
|
|
102
|
+
expect(pushedTops[pushedTops.length - 1]).toBeCloseTo(closedPushedTop, 0);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import DSBannerCO from '../DSBannerCO';
|
|
2
|
+
import { axeCoreCheck } from '../../helpers';
|
|
3
|
+
|
|
4
|
+
if (
|
|
5
|
+
(!browser.capabilities['ice:options'].isPhone &&
|
|
6
|
+
!browser.capabilities['ice:options'].isTablet &&
|
|
7
|
+
browser.capabilities.browserName === 'chrome') ||
|
|
8
|
+
browser.capabilities.browserName === 'Chrome'
|
|
9
|
+
) {
|
|
10
|
+
// Coverage for PUI-17935 (slots implementation and Dimsum slot compliance)
|
|
11
|
+
describe('PUI-19263 - DSBanner:: slots theming - AxeCore', () => {
|
|
12
|
+
before('loading page', async () => {
|
|
13
|
+
const errorOnGo = await DSBannerCO.slotsTest.go();
|
|
14
|
+
if (errorOnGo) throw errorOnGo;
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('01: should display the banners customized using slots and pass axecore test', async () => {
|
|
18
|
+
const banner = await DSBannerCO.getContainerSlotByIndex();
|
|
19
|
+
await banner.waitForDisplayed();
|
|
20
|
+
const result = await axeCoreCheck();
|
|
21
|
+
expect(result.length).toBe(0);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|