Skip to content

Commit 76ba284

Browse files
committed
Transform ScrollView jest tests into playwright (#598)
1 parent 36bb792 commit 76ba284

61 files changed

Lines changed: 801 additions & 152 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
import React from 'react';
2+
import {
3+
expect,
4+
test,
5+
} from '@playwright/experimental-ct-react';
6+
import {
7+
mixPropTests,
8+
propTests,
9+
} from '../../../../tests/playwright';
10+
import {
11+
ScrollViewForDetectEndAutoscrollTest,
12+
ScrollViewForRefTest,
13+
ScrollViewForTest,
14+
} from './ScrollView.story';
15+
import { arrowsPropTest } from './_propTests/arrowsPropTest';
16+
import { directionPropTest } from './_propTests/directionPropTest';
17+
import { nextArrowColorPropTest } from './_propTests/nextArrowColorPropTest';
18+
import { nextArrowElementPropTest } from './_propTests/nextArrowElementPropTest';
19+
import { prevArrowColorPropTest } from './_propTests/prevArrowColorPropTest';
20+
import { prevArrowElementPropTest } from './_propTests/prevArrowElementPropTest';
21+
import { endShadowBackgroundPropTest } from './_propTests/endShadowBackgroundPropTest';
22+
import { startShadowBackgroundPropTest } from './_propTests/startShadowBackgroundPropTest';
23+
import { endShadowSizePropTest } from './_propTests/endShadowSizePropTest';
24+
import { startShadowSizePropTest } from './_propTests/startShadowSizePropTest';
25+
import { shadowsPropTest } from './_propTests/shadowsPropTest';
26+
import type { ExtendedWindow } from './types';
27+
28+
test.describe('ScrollView', () => {
29+
test.describe('visual', () => {
30+
[
31+
...propTests.defaultComponentPropTest,
32+
...mixPropTests([
33+
arrowsPropTest,
34+
directionPropTest,
35+
]),
36+
...mixPropTests([
37+
endShadowBackgroundPropTest,
38+
directionPropTest,
39+
]),
40+
...mixPropTests([
41+
endShadowSizePropTest,
42+
directionPropTest,
43+
]),
44+
...nextArrowColorPropTest,
45+
...nextArrowElementPropTest,
46+
...prevArrowColorPropTest,
47+
...prevArrowElementPropTest,
48+
...shadowsPropTest,
49+
...mixPropTests([
50+
startShadowBackgroundPropTest,
51+
directionPropTest,
52+
]),
53+
...mixPropTests([
54+
startShadowSizePropTest,
55+
directionPropTest,
56+
]),
57+
].forEach(({
58+
name,
59+
onBeforeTest,
60+
onBeforeSnapshot,
61+
props,
62+
}) => {
63+
test(name, async ({
64+
mount,
65+
page,
66+
}) => {
67+
if (onBeforeTest) {
68+
await onBeforeTest(page);
69+
}
70+
71+
const component = await mount(
72+
<ScrollViewForTest
73+
{...props}
74+
/>,
75+
);
76+
77+
/**
78+
* Because onBeforeSnapshot is not propagated through mixPropTests
79+
*/
80+
if (
81+
props?.startShadowBackground !== undefined
82+
|| props?.startShadowSize !== undefined
83+
) {
84+
await page.evaluate((id) => {
85+
(window as ExtendedWindow).scrollEnd = false;
86+
const parent = document.getElementById(id);
87+
parent.children[0].addEventListener('scrollend', () => {
88+
(window as ExtendedWindow).scrollEnd = true;
89+
}, { once: true });
90+
}, 'scrollbar');
91+
92+
if (props?.direction === 'horizontal') {
93+
await page.evaluate((id) => {
94+
const parent = document.getElementById(id);
95+
parent.children[0].scrollLeft += 124;
96+
}, 'scrollbar');
97+
} else {
98+
await page.evaluate((id) => {
99+
const parent = document.getElementById(id);
100+
parent.children[0].scrollTop += 124;
101+
}, 'scrollbar');
102+
}
103+
104+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
105+
}
106+
107+
if (onBeforeSnapshot) {
108+
await onBeforeSnapshot(page, component);
109+
}
110+
111+
const screenshot = await component.screenshot({ animations: 'disabled' });
112+
expect(screenshot).toMatchSnapshot();
113+
});
114+
});
115+
});
116+
117+
test.describe('non-visual', () => {
118+
test('id', async ({ mount }) => {
119+
const id = 'testId';
120+
121+
const component = await mount(
122+
<ScrollViewForTest
123+
arrows
124+
id={id}
125+
/>,
126+
);
127+
128+
expect(component.locator(`div[id="${id}"]`)).toBeDefined();
129+
expect(component.locator(`div[id="${id}__content"]`)).toBeDefined();
130+
expect(component.locator(`div[id="${id}__arrowPrevButton"]`)).toBeDefined();
131+
expect(component.locator(`div[id="${id}__arrowNextButton"]`)).toBeDefined();
132+
});
133+
134+
test('ref', async ({ mount }) => {
135+
const id = 'testId';
136+
137+
const component = await mount(
138+
<ScrollViewForRefTest
139+
id={id}
140+
testRefAttrName="test-ref"
141+
testRefAttrValue="test-ref-value"
142+
/>,
143+
);
144+
145+
const refValue = await component.evaluate((_, idArg) => document.getElementById(idArg).firstElementChild.getAttribute('test-ref'), id);
146+
147+
expect(refValue).toBe('test-ref-value');
148+
});
149+
});
150+
151+
test.describe('functionality', () => {
152+
test('scroll by arrowScrollStep when click on arrow', async ({
153+
mount,
154+
page,
155+
}) => {
156+
const id = 'testId';
157+
158+
const component = await mount(
159+
<ScrollViewForTest
160+
arrows
161+
arrowsScrollStep={600}
162+
id={id}
163+
/>,
164+
);
165+
166+
const arrow = component.locator(`button[id="${id}__arrowNextButton"]`);
167+
await page.evaluate((idArg) => {
168+
const parent = document.getElementById(idArg);
169+
parent.children[0].setAttribute('style', 'scroll-behavior: unset;');
170+
}, id);
171+
const scroll = component.locator(`div[id="${id}"] > div:first-child`);
172+
await arrow.click();
173+
174+
const atrValue = await scroll.evaluate((element) => element.scrollTop);
175+
176+
expect(atrValue).toBe(600);
177+
});
178+
179+
test('scroll at end when content change and autoScroll is "always"', async ({
180+
mount,
181+
page,
182+
}) => {
183+
const id = 'testId';
184+
185+
const component = await mount(
186+
<ScrollViewForTest
187+
autoScroll="always"
188+
id={id}
189+
/>,
190+
);
191+
192+
await page.evaluate((idArg) => {
193+
(window as ExtendedWindow).scrollEnd = false;
194+
const parent = document.getElementById(idArg);
195+
parent.children[0].setAttribute('style', 'scroll-behavior: unset;');
196+
}, id);
197+
198+
await page.evaluate((idArg) => {
199+
const parent = document.getElementById(idArg);
200+
parent.children[0].addEventListener('scrollend', () => {
201+
(window as ExtendedWindow).scrollEnd = true;
202+
});
203+
parent.children[0].textContent += 'content fragment content fragment content fragment';
204+
}, id);
205+
206+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
207+
208+
const scroll = component.locator(`div[id="${id}"] > div:first-child`);
209+
const atrValue = await scroll.evaluate((element) => element.scrollTop);
210+
211+
expect(atrValue).not.toBe(0);
212+
});
213+
214+
test('scroll at end when scrolled down and content change and autoScroll is "detectEnd"', async ({
215+
mount,
216+
page,
217+
}) => {
218+
const id = 'testId';
219+
let initialScrollTop = 0;
220+
221+
await page.exposeFunction('onScrollEnd', (value: number) => {
222+
initialScrollTop = value;
223+
});
224+
225+
const component = await mount(
226+
<ScrollViewForDetectEndAutoscrollTest
227+
id={id}
228+
/>,
229+
);
230+
231+
/**
232+
* First need to wait for initial scroll down.
233+
*/
234+
await page.evaluate((idArg) => {
235+
(window as ExtendedWindow).scrollEnd = false;
236+
237+
const parent = document.getElementById(idArg);
238+
parent.children[0].addEventListener('scrollend', () => {
239+
(window as ExtendedWindow).scrollEnd = true;
240+
(window as ExtendedWindow)?.onScrollEnd(parent.children[0].scrollTop);
241+
}, { once: true });
242+
}, id);
243+
244+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
245+
246+
/**
247+
* Add scroll detect setup.
248+
*/
249+
await page.evaluate((idArg) => {
250+
(window as ExtendedWindow).scrollEnd = false;
251+
const parent = document.getElementById(idArg);
252+
parent.children[0].addEventListener('scrollend', () => {
253+
(window as ExtendedWindow).scrollEnd = true;
254+
});
255+
}, id);
256+
257+
const button = component.getByRole('button');
258+
await button.click();
259+
260+
/**
261+
* Wait for scroll down.
262+
*/
263+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
264+
265+
const scrollTopAfter = await page.evaluate((idArg) => {
266+
const parent = document.getElementById(idArg);
267+
return parent.children[0].scrollTop;
268+
}, id);
269+
270+
expect(scrollTopAfter).toBeGreaterThan(initialScrollTop);
271+
});
272+
273+
test('do not display top arrow after scroll before debounce expires', async ({
274+
mount,
275+
page,
276+
}) => {
277+
const id = 'testId';
278+
const debounceTimeout = 2000;
279+
280+
const component = await mount(
281+
<ScrollViewForTest
282+
arrows
283+
debounce={debounceTimeout}
284+
id={id}
285+
/>,
286+
);
287+
288+
/**
289+
* Setup scroll down listener.
290+
*/
291+
await page.evaluate((idArg) => {
292+
(window as ExtendedWindow).scrollEnd = false;
293+
const parent = document.getElementById(idArg);
294+
parent.children[0].addEventListener('scrollend', () => {
295+
(window as ExtendedWindow).scrollEnd = true;
296+
}, { once: true });
297+
}, id);
298+
299+
/**
300+
* Scroll down
301+
*/
302+
await page.evaluate((idArg) => {
303+
const parent = document.getElementById(idArg);
304+
parent.children[0].scrollTop += 200;
305+
}, id);
306+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
307+
308+
const bottomArrowAfter = component.locator(`button[id="${id}__arrowPrevButton"]`);
309+
await expect(bottomArrowAfter).not.toBeVisible();
310+
});
311+
312+
test('do not display bottom arrow after scroll when debounce expires', async ({
313+
mount,
314+
page,
315+
}) => {
316+
const id = 'testId';
317+
const debounceTimeout = 5000;
318+
319+
const component = await mount(
320+
<ScrollViewForTest
321+
arrows
322+
debounce={debounceTimeout}
323+
id={id}
324+
/>,
325+
);
326+
327+
/**
328+
* Setup scroll down listener.
329+
*/
330+
await page.evaluate((idArg) => {
331+
(window as ExtendedWindow).scrollEnd = false;
332+
const parent = document.getElementById(idArg);
333+
parent.children[0].addEventListener('scrollend', () => {
334+
(window as ExtendedWindow).scrollEnd = true;
335+
}, { once: true });
336+
}, id);
337+
338+
/**
339+
* Scroll down
340+
*/
341+
await page.evaluate((idArg) => {
342+
const parent = document.getElementById(idArg);
343+
parent.children[0].scrollTop = parent.children[0].children[0].clientHeight;
344+
}, id);
345+
await page.waitForFunction(() => (window as ExtendedWindow).scrollEnd === true);
346+
347+
const bottomArrowBefore = component.locator(`button[id="${id}__arrowNextButton"]`);
348+
await expect(bottomArrowBefore).toBeVisible();
349+
350+
/**
351+
* Wait on debounce timeout to expire.
352+
*/
353+
await page.waitForTimeout(1.5 * debounceTimeout);
354+
355+
const bottomArrowAfter = component.locator(`button[id="${id}__arrowNextButton"]`);
356+
await expect(bottomArrowAfter).not.toBeVisible();
357+
});
358+
});
359+
});

0 commit comments

Comments
 (0)