From 12a5335b356cc33543765ccc08304bf631e3f170 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 13 Dec 2023 10:29:41 +0100 Subject: [PATCH 1/7] Add option to pass `contentSize` and `layoutMeasurement` when calling `scrollTo` --- src/user-event/event-builder/scroll-view.ts | 16 +++++-- src/user-event/scroll/scroll-to.ts | 53 ++++++++++++++++----- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/user-event/event-builder/scroll-view.ts b/src/user-event/event-builder/scroll-view.ts index b322ec099..64b58f3ef 100644 --- a/src/user-event/event-builder/scroll-view.ts +++ b/src/user-event/event-builder/scroll-view.ts @@ -1,3 +1,5 @@ +import type { ScrollToOptions } from '../scroll'; + /** * Experimental values: * - iOS: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 5.333333333333333}, "contentSize": {"height": 1676.6666259765625, "width": 390}, "layoutMeasurement": {"height": 753, "width": 390}, "zoomScale": 1}` @@ -13,15 +15,21 @@ export interface ContentOffset { } export const ScrollViewEventBuilder = { - scroll: (offset: ContentOffset = { y: 0, x: 0 }) => { + scroll: ( + offset: ContentOffset = { y: 0, x: 0 }, + options?: ScrollToOptions + ) => { return { nativeEvent: { contentInset: { bottom: 0, left: 0, right: 0, top: 0 }, contentOffset: { y: offset.y, x: offset.x }, - contentSize: { height: 0, width: 0 }, + contentSize: { + height: options?.contentSize?.height ?? 0, + width: options?.contentSize?.width ?? 0, + }, layoutMeasurement: { - height: 0, - width: 0, + height: options?.layoutMeasurement?.height ?? 0, + width: options?.layoutMeasurement?.width ?? 0, }, responderIgnoreScroll: true, target: 0, diff --git a/src/user-event/scroll/scroll-to.ts b/src/user-event/scroll/scroll-to.ts index 6ddd066be..7054165b3 100644 --- a/src/user-event/scroll/scroll-to.ts +++ b/src/user-event/scroll/scroll-to.ts @@ -7,6 +7,7 @@ import { isHostScrollView } from '../../helpers/host-component-names'; import { pick } from '../../helpers/object'; import { dispatchEvent, wait } from '../utils'; import { ContentOffset } from '../event-builder/scroll-view'; +import fireEvent from '../../fire-event'; import { createScrollSteps, inertialInterpolator, @@ -14,7 +15,19 @@ import { } from './utils'; import { getElementScrollOffset, setElementScrollOffset } from './state'; -export interface VerticalScrollToOptions { +interface CommonScrollToOptions { + contentSize?: { + height: number; + width: number; + }; + + layoutMeasurement?: { + height: number; + width: number; + }; +} + +export interface VerticalScrollToOptions extends CommonScrollToOptions { y: number; momentumY?: number; @@ -23,7 +36,7 @@ export interface VerticalScrollToOptions { momentumX?: never; } -export interface HorizontalScrollToOptions { +export interface HorizontalScrollToOptions extends CommonScrollToOptions { x: number; momentumX?: number; @@ -50,13 +63,15 @@ export async function scrollTo( ensureScrollViewDirection(element, options); + emitContentSizeChangeEvent(element, options); + const initialPosition = getElementScrollOffset(element); const dragSteps = createScrollSteps( { y: options.y, x: options.x }, initialPosition, linearInterpolator ); - await emitDragScrollEvents(this.config, element, dragSteps); + await emitDragScrollEvents(this.config, element, dragSteps, options); const momentumStart = dragSteps.at(-1) ?? initialPosition; const momentumSteps = createScrollSteps( @@ -64,17 +79,30 @@ export async function scrollTo( momentumStart, inertialInterpolator ); - await emitMomentumScrollEvents(this.config, element, momentumSteps); + await emitMomentumScrollEvents(this.config, element, momentumSteps, options); const finalPosition = momentumSteps.at(-1) ?? dragSteps.at(-1) ?? initialPosition; setElementScrollOffset(element, finalPosition); } +function emitContentSizeChangeEvent( + element: ReactTestInstance, + options: ScrollToOptions +) { + fireEvent( + element, + 'contentSizeChange', + options.contentSize?.width ?? 0, + options.contentSize?.height ?? 0 + ); +} + async function emitDragScrollEvents( config: UserEventConfig, element: ReactTestInstance, - scrollSteps: ContentOffset[] + scrollSteps: ContentOffset[], + scrollOptions: ScrollToOptions ) { if (scrollSteps.length === 0) { return; @@ -84,7 +112,7 @@ async function emitDragScrollEvents( dispatchEvent( element, 'scrollBeginDrag', - EventBuilder.ScrollView.scroll(scrollSteps[0]) + EventBuilder.ScrollView.scroll(scrollSteps[0], scrollOptions) ); // Note: experimentally, in case of drag scroll the last scroll step @@ -95,7 +123,7 @@ async function emitDragScrollEvents( dispatchEvent( element, 'scroll', - EventBuilder.ScrollView.scroll(scrollSteps[i]) + EventBuilder.ScrollView.scroll(scrollSteps[i], scrollOptions) ); } @@ -104,14 +132,15 @@ async function emitDragScrollEvents( dispatchEvent( element, 'scrollEndDrag', - EventBuilder.ScrollView.scroll(lastStep) + EventBuilder.ScrollView.scroll(lastStep, scrollOptions) ); } async function emitMomentumScrollEvents( config: UserEventConfig, element: ReactTestInstance, - scrollSteps: ContentOffset[] + scrollSteps: ContentOffset[], + scrollOptions: ScrollToOptions ) { if (scrollSteps.length === 0) { return; @@ -121,7 +150,7 @@ async function emitMomentumScrollEvents( dispatchEvent( element, 'momentumScrollBegin', - EventBuilder.ScrollView.scroll(scrollSteps[0]) + EventBuilder.ScrollView.scroll(scrollSteps[0], scrollOptions) ); // Note: experimentally, in case of momentum scroll the last scroll step @@ -132,7 +161,7 @@ async function emitMomentumScrollEvents( dispatchEvent( element, 'scroll', - EventBuilder.ScrollView.scroll(scrollSteps[i]) + EventBuilder.ScrollView.scroll(scrollSteps[i], scrollOptions) ); } @@ -141,7 +170,7 @@ async function emitMomentumScrollEvents( dispatchEvent( element, 'momentumScrollEnd', - EventBuilder.ScrollView.scroll(lastStep) + EventBuilder.ScrollView.scroll(lastStep, scrollOptions) ); } From 3f10d7338df924ee49f2ed928565bd44733c9625 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 13 Dec 2023 10:35:41 +0100 Subject: [PATCH 2/7] Update docs --- website/docs/UserEvent.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/docs/UserEvent.md b/website/docs/UserEvent.md index 363e2a094..87bd91c79 100644 --- a/website/docs/UserEvent.md +++ b/website/docs/UserEvent.md @@ -204,9 +204,13 @@ scrollTo( options: { y: number, momentumY?: number, + contentSize?: { width: number, height: number }, + layoutMeasurement?: { width: number, height: number }, } | { x: number, momentumX?: number, + contentSize?: { width: number, height: number }, + layoutMeasurement?: { width: number, height: number }, } ``` @@ -221,6 +225,8 @@ This helper simulates user scrolling a host `ScrollView` element. This function supports only host `ScrollView` elements, passing other element types will result in error. Note that `FlatList` is accepted as it renders to a host `ScrolLView` element, however in the current iteration we focus only on base `ScrollView` only features. +If you want to simulate scrolling a `FlatList` or any other `VirtualizedList`, you should also pass `contentSize` and `layoutMeasurement` options, to run underlying logic that updates the currently visible window. + Scroll interaction should match `ScrollView` element direction. For vertical scroll view (default or explicit `horizontal={false}`) you should pass only `y` (and optionally also `momentumY`) option, for horizontal scroll view (`horizontal={true}`) you should pass only `x` (and optionally `momentumX`) option. Each scroll interaction consists of a mandatory drag scroll part which simulates user dragging the scroll view with his finger (`y` or `x` option). This may optionally be followed by a momentum scroll movement which simulates the inertial movement of scroll view content after the user lifts his finger up (`momentumY` or `momentumX` options). From 6e2e6c2ddc4427a4a7a8245c927b04a59cd37c5b Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 15 Dec 2023 16:00:41 +0100 Subject: [PATCH 3/7] Add tests --- src/__tests__/scroll-to-flatlist.test.tsx | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/__tests__/scroll-to-flatlist.test.tsx diff --git a/src/__tests__/scroll-to-flatlist.test.tsx b/src/__tests__/scroll-to-flatlist.test.tsx new file mode 100644 index 000000000..fef8c679a --- /dev/null +++ b/src/__tests__/scroll-to-flatlist.test.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { View, FlatList, Text } from 'react-native'; +import { render, screen, userEvent } from '..'; + +const DATA = new Array(100).fill(0).map((_, i) => `Item ${i}`); + +function Item({ title }: { title: string }) { + return ( + + {title} + + ); +} + +function Scrollable() { + return ( + + } + initialNumToRender={10} + updateCellsBatchingPeriod={0} + /> + + ); +} + +test('scrollTo with contentSize and layoutMeasurement causes FlatList to update its content', async () => { + render(); + + const flatlist = screen.getByTestId('test-flatlist'); + + const item1 = screen.queryByText('Item 0'); + const item2 = screen.queryByText('Item 7'); + + const user = userEvent.setup(); + await user.scrollTo(flatlist, { + y: 300, + contentSize: { width: 240, height: 480 }, + layoutMeasurement: { width: 240, height: 480 }, + }); + + const item3 = screen.queryByText('Item 15'); + + expect(item1).not.toBeNull(); + expect(item2).not.toBeNull(); + expect(item3).not.toBeNull(); +}); + +test('scrollTo without contentSize and layoutMeasurement does not cause FlatList to update its content', async () => { + render(); + + const flatlist = screen.getByTestId('test-flatlist'); + + const item1 = screen.queryByText('Item 0'); + const item2 = screen.queryByText('Item 7'); + + const user = userEvent.setup(); + await user.scrollTo(flatlist, { y: 300 }); + + const item3 = screen.queryByText('Item 15'); + + expect(item1).not.toBeNull(); + expect(item2).not.toBeNull(); + expect(item3).toBeNull(); +}); From a021500cd99e6c1249f983ef21b260739fb09b07 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 15 Dec 2023 18:15:25 +0100 Subject: [PATCH 4/7] refactor: code review changes --- src/user-event/event-builder/scroll-view.ts | 29 ++++++++---- ....tsx.snap => scroll-to-flat-list.tsx.snap} | 0 ....test.tsx.snap => scroll-to.test.tsx.snap} | 0 ...o-flatList.tsx => scroll-to-flat-list.tsx} | 46 ++++++++++++++++++- .../{scrollTo.test.tsx => scroll-to.test.tsx} | 0 src/user-event/scroll/scroll-to.ts | 6 +-- src/user-event/utils/dispatch-event.ts | 6 +-- 7 files changed, 70 insertions(+), 17 deletions(-) rename src/user-event/scroll/__tests__/__snapshots__/{scrollTo-flatList.tsx.snap => scroll-to-flat-list.tsx.snap} (100%) rename src/user-event/scroll/__tests__/__snapshots__/{scrollTo.test.tsx.snap => scroll-to.test.tsx.snap} (100%) rename src/user-event/scroll/__tests__/{scrollTo-flatList.tsx => scroll-to-flat-list.tsx} (63%) rename src/user-event/scroll/__tests__/{scrollTo.test.tsx => scroll-to.test.tsx} (100%) diff --git a/src/user-event/event-builder/scroll-view.ts b/src/user-event/event-builder/scroll-view.ts index 64b58f3ef..6a9d8e5de 100644 --- a/src/user-event/event-builder/scroll-view.ts +++ b/src/user-event/event-builder/scroll-view.ts @@ -1,11 +1,3 @@ -import type { ScrollToOptions } from '../scroll'; - -/** - * Experimental values: - * - iOS: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 5.333333333333333}, "contentSize": {"height": 1676.6666259765625, "width": 390}, "layoutMeasurement": {"height": 753, "width": 390}, "zoomScale": 1}` - * - Android: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 31.619047164916992}, "contentSize": {"height": 1624.761962890625, "width": 411.4285583496094}, "layoutMeasurement": {"height": 785.5238037109375, "width": 411.4285583496094}, "responderIgnoreScroll": true, "target": 139, "velocity": {"x": -1.3633992671966553, "y": -1.3633992671966553}}` - */ - /** * Scroll position of a scrollable element. */ @@ -14,10 +6,29 @@ export interface ContentOffset { x: number; } +/** + * Other options for constructing a scroll event. + */ +export type ScrollEventOptions = { + contentSize?: { + height: number; + width: number; + }; + layoutMeasurement?: { + height: number; + width: number; + }; +}; + +/** + * Experimental values: + * - iOS: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 5.333333333333333}, "contentSize": {"height": 1676.6666259765625, "width": 390}, "layoutMeasurement": {"height": 753, "width": 390}, "zoomScale": 1}` + * - Android: `{"contentInset": {"bottom": 0, "left": 0, "right": 0, "top": 0}, "contentOffset": {"x": 0, "y": 31.619047164916992}, "contentSize": {"height": 1624.761962890625, "width": 411.4285583496094}, "layoutMeasurement": {"height": 785.5238037109375, "width": 411.4285583496094}, "responderIgnoreScroll": true, "target": 139, "velocity": {"x": -1.3633992671966553, "y": -1.3633992671966553}}` + */ export const ScrollViewEventBuilder = { scroll: ( offset: ContentOffset = { y: 0, x: 0 }, - options?: ScrollToOptions + options?: ScrollEventOptions ) => { return { nativeEvent: { diff --git a/src/user-event/scroll/__tests__/__snapshots__/scrollTo-flatList.tsx.snap b/src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.tsx.snap similarity index 100% rename from src/user-event/scroll/__tests__/__snapshots__/scrollTo-flatList.tsx.snap rename to src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.tsx.snap diff --git a/src/user-event/scroll/__tests__/__snapshots__/scrollTo.test.tsx.snap b/src/user-event/scroll/__tests__/__snapshots__/scroll-to.test.tsx.snap similarity index 100% rename from src/user-event/scroll/__tests__/__snapshots__/scrollTo.test.tsx.snap rename to src/user-event/scroll/__tests__/__snapshots__/scroll-to.test.tsx.snap diff --git a/src/user-event/scroll/__tests__/scrollTo-flatList.tsx b/src/user-event/scroll/__tests__/scroll-to-flat-list.tsx similarity index 63% rename from src/user-event/scroll/__tests__/scrollTo-flatList.tsx rename to src/user-event/scroll/__tests__/scroll-to-flat-list.tsx index 67dcc1a28..5a36eb958 100644 --- a/src/user-event/scroll/__tests__/scrollTo-flatList.tsx +++ b/src/user-event/scroll/__tests__/scroll-to-flat-list.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; -import { FlatList, ScrollViewProps, Text } from 'react-native'; +import { FlatList, ScrollViewProps, Text, View } from 'react-native'; import { EventEntry, createEventLogger } from '../../../test-utils'; import { render, screen } from '../../..'; import { userEvent } from '../..'; +import '../../../matchers/extend-expect'; const data = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; @@ -68,3 +69,46 @@ describe('scrollTo() with FlatList', () => { ]); }); }); + +const DATA = new Array(100).fill(0).map((_, i) => `Item ${i}`); + +function Scrollable() { + return ( + + } + initialNumToRender={10} + updateCellsBatchingPeriod={0} + /> + + ); +} + +function Item({ title }: { title: string }) { + return ( + + {title} + + ); +} + +test('scrollTo with contentSize and layoutMeasurement update FlatList content', async () => { + render(); + const user = userEvent.setup(); + + expect(screen.getByText('Item 0')).toBeOnTheScreen(); + expect(screen.getByText('Item 7')).toBeOnTheScreen(); + expect(screen.queryByText('Item 15')).not.toBeOnTheScreen(); + + await user.scrollTo(screen.getByTestId('flat-list'), { + y: 300, + contentSize: { width: 240, height: 480 }, + layoutMeasurement: { width: 240, height: 480 }, + }); + + expect(screen.getByText('Item 0')).toBeOnTheScreen(); + expect(screen.getByText('Item 7')).toBeOnTheScreen(); + expect(screen.getByText('Item 15')).toBeOnTheScreen(); +}); diff --git a/src/user-event/scroll/__tests__/scrollTo.test.tsx b/src/user-event/scroll/__tests__/scroll-to.test.tsx similarity index 100% rename from src/user-event/scroll/__tests__/scrollTo.test.tsx rename to src/user-event/scroll/__tests__/scroll-to.test.tsx diff --git a/src/user-event/scroll/scroll-to.ts b/src/user-event/scroll/scroll-to.ts index 7054165b3..39c424a51 100644 --- a/src/user-event/scroll/scroll-to.ts +++ b/src/user-event/scroll/scroll-to.ts @@ -5,9 +5,8 @@ import { EventBuilder } from '../event-builder'; import { ErrorWithStack } from '../../helpers/errors'; import { isHostScrollView } from '../../helpers/host-component-names'; import { pick } from '../../helpers/object'; -import { dispatchEvent, wait } from '../utils'; import { ContentOffset } from '../event-builder/scroll-view'; -import fireEvent from '../../fire-event'; +import { dispatchEvent, wait } from '../utils'; import { createScrollSteps, inertialInterpolator, @@ -20,7 +19,6 @@ interface CommonScrollToOptions { height: number; width: number; }; - layoutMeasurement?: { height: number; width: number; @@ -90,7 +88,7 @@ function emitContentSizeChangeEvent( element: ReactTestInstance, options: ScrollToOptions ) { - fireEvent( + dispatchEvent( element, 'contentSizeChange', options.contentSize?.width ?? 0, diff --git a/src/user-event/utils/dispatch-event.ts b/src/user-event/utils/dispatch-event.ts index a8c6ad91c..76a9d3384 100644 --- a/src/user-event/utils/dispatch-event.ts +++ b/src/user-event/utils/dispatch-event.ts @@ -6,12 +6,12 @@ import act from '../../act'; * * @param element element trigger event on * @param eventName name of the event - * @param event event payload + * @param event event payload(s) */ export function dispatchEvent( element: ReactTestInstance, eventName: string, - event: unknown + ...event: unknown[] ) { const handler = getEventHandler(element, eventName); if (!handler) { @@ -20,7 +20,7 @@ export function dispatchEvent( // This will be called synchronously. void act(() => { - handler(event); + handler(...event); }); } From 711722ecb47f2b50c10eeac8fa9dd1b84f467226 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 15 Dec 2023 18:16:29 +0100 Subject: [PATCH 5/7] refactor: code review changes --- src/__tests__/scroll-to-flatlist.test.tsx | 67 ----------------------- 1 file changed, 67 deletions(-) delete mode 100644 src/__tests__/scroll-to-flatlist.test.tsx diff --git a/src/__tests__/scroll-to-flatlist.test.tsx b/src/__tests__/scroll-to-flatlist.test.tsx deleted file mode 100644 index fef8c679a..000000000 --- a/src/__tests__/scroll-to-flatlist.test.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; -import { View, FlatList, Text } from 'react-native'; -import { render, screen, userEvent } from '..'; - -const DATA = new Array(100).fill(0).map((_, i) => `Item ${i}`); - -function Item({ title }: { title: string }) { - return ( - - {title} - - ); -} - -function Scrollable() { - return ( - - } - initialNumToRender={10} - updateCellsBatchingPeriod={0} - /> - - ); -} - -test('scrollTo with contentSize and layoutMeasurement causes FlatList to update its content', async () => { - render(); - - const flatlist = screen.getByTestId('test-flatlist'); - - const item1 = screen.queryByText('Item 0'); - const item2 = screen.queryByText('Item 7'); - - const user = userEvent.setup(); - await user.scrollTo(flatlist, { - y: 300, - contentSize: { width: 240, height: 480 }, - layoutMeasurement: { width: 240, height: 480 }, - }); - - const item3 = screen.queryByText('Item 15'); - - expect(item1).not.toBeNull(); - expect(item2).not.toBeNull(); - expect(item3).not.toBeNull(); -}); - -test('scrollTo without contentSize and layoutMeasurement does not cause FlatList to update its content', async () => { - render(); - - const flatlist = screen.getByTestId('test-flatlist'); - - const item1 = screen.queryByText('Item 0'); - const item2 = screen.queryByText('Item 7'); - - const user = userEvent.setup(); - await user.scrollTo(flatlist, { y: 300 }); - - const item3 = screen.queryByText('Item 15'); - - expect(item1).not.toBeNull(); - expect(item2).not.toBeNull(); - expect(item3).toBeNull(); -}); From c1f58dd295695b00a38ccca7fdfe9933289d34d8 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 15 Dec 2023 18:27:21 +0100 Subject: [PATCH 6/7] refactor: code review changes --- ...snap => scroll-to-flat-list.test.tsx.snap} | 0 ...-list.tsx => scroll-to-flat-list.test.tsx} | 4 ++-- src/user-event/scroll/scroll-to.ts | 19 ++++++------------- website/docs/UserEvent.md | 12 +++++++----- 4 files changed, 15 insertions(+), 20 deletions(-) rename src/user-event/scroll/__tests__/__snapshots__/{scroll-to-flat-list.tsx.snap => scroll-to-flat-list.test.tsx.snap} (100%) rename src/user-event/scroll/__tests__/{scroll-to-flat-list.tsx => scroll-to-flat-list.test.tsx} (100%) diff --git a/src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.tsx.snap b/src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.test.tsx.snap similarity index 100% rename from src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.tsx.snap rename to src/user-event/scroll/__tests__/__snapshots__/scroll-to-flat-list.test.tsx.snap diff --git a/src/user-event/scroll/__tests__/scroll-to-flat-list.tsx b/src/user-event/scroll/__tests__/scroll-to-flat-list.test.tsx similarity index 100% rename from src/user-event/scroll/__tests__/scroll-to-flat-list.tsx rename to src/user-event/scroll/__tests__/scroll-to-flat-list.test.tsx index 5a36eb958..30cff931e 100644 --- a/src/user-event/scroll/__tests__/scroll-to-flat-list.tsx +++ b/src/user-event/scroll/__tests__/scroll-to-flat-list.test.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { FlatList, ScrollViewProps, Text, View } from 'react-native'; -import { EventEntry, createEventLogger } from '../../../test-utils'; import { render, screen } from '../../..'; -import { userEvent } from '../..'; import '../../../matchers/extend-expect'; +import { EventEntry, createEventLogger } from '../../../test-utils'; +import { userEvent } from '../..'; const data = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; diff --git a/src/user-event/scroll/scroll-to.ts b/src/user-event/scroll/scroll-to.ts index 39c424a51..082152e17 100644 --- a/src/user-event/scroll/scroll-to.ts +++ b/src/user-event/scroll/scroll-to.ts @@ -61,7 +61,12 @@ export async function scrollTo( ensureScrollViewDirection(element, options); - emitContentSizeChangeEvent(element, options); + dispatchEvent( + element, + 'contentSizeChange', + options.contentSize?.width ?? 0, + options.contentSize?.height ?? 0 + ); const initialPosition = getElementScrollOffset(element); const dragSteps = createScrollSteps( @@ -84,18 +89,6 @@ export async function scrollTo( setElementScrollOffset(element, finalPosition); } -function emitContentSizeChangeEvent( - element: ReactTestInstance, - options: ScrollToOptions -) { - dispatchEvent( - element, - 'contentSizeChange', - options.contentSize?.width ?? 0, - options.contentSize?.height ?? 0 - ); -} - async function emitDragScrollEvents( config: UserEventConfig, element: ReactTestInstance, diff --git a/website/docs/UserEvent.md b/website/docs/UserEvent.md index 87bd91c79..f2361809c 100644 --- a/website/docs/UserEvent.md +++ b/website/docs/UserEvent.md @@ -223,24 +223,26 @@ await user.scrollTo(scrollView, { y: 100, momentumY: 200 }); This helper simulates user scrolling a host `ScrollView` element. -This function supports only host `ScrollView` elements, passing other element types will result in error. Note that `FlatList` is accepted as it renders to a host `ScrolLView` element, however in the current iteration we focus only on base `ScrollView` only features. - -If you want to simulate scrolling a `FlatList` or any other `VirtualizedList`, you should also pass `contentSize` and `layoutMeasurement` options, to run underlying logic that updates the currently visible window. +This function supports only host `ScrollView` elements, passing other element types will result in error. Note that `FlatList` is accepted as it renders to a host `ScrolLView` element. Scroll interaction should match `ScrollView` element direction. For vertical scroll view (default or explicit `horizontal={false}`) you should pass only `y` (and optionally also `momentumY`) option, for horizontal scroll view (`horizontal={true}`) you should pass only `x` (and optionally `momentumX`) option. Each scroll interaction consists of a mandatory drag scroll part which simulates user dragging the scroll view with his finger (`y` or `x` option). This may optionally be followed by a momentum scroll movement which simulates the inertial movement of scroll view content after the user lifts his finger up (`momentumY` or `momentumX` options). -### Options {#type-options} +### Options {#scroll-to-options} - `y` - target vertical drag scroll position - `x` - target horizontal drag scroll position - `momentumY` - target vertical momentum scroll position - `momentumX` - target horizontal momentum scroll position +- `contentSize` - passed to `ScrollView` events and enabling `FlatList` updates +- `layoutMeasurement` - passed to `ScrollView` events and enabling `FlatList` updates User Event will generate a number of intermediate scroll steps to simulate user scroll interaction. You should not rely on exact number or values of these scrolls steps as they might be change in the future version. -This function will remember where the last scroll ended, so subsequent scroll interaction will starts from that positition. The initial scroll position will be assumed to be `{ y: 0, x: 0 }`. +This function will remember where the last scroll ended, so subsequent scroll interaction will starts from that position. The initial scroll position will be assumed to be `{ y: 0, x: 0 }`. + +In order to simulate a `FlatList` (and other controls based on `VirtualizedList`) scrolling, you should pass `contentSize` and `layoutMeasurement` options, which enable the underlying logic to update the currently visible window. ### Sequence of events From 1b16e92e48ec345dcabfc2e4e23d877772f2a66d Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Fri, 15 Dec 2023 18:29:19 +0100 Subject: [PATCH 7/7] docs: fix typo --- website/docs/UserEvent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/UserEvent.md b/website/docs/UserEvent.md index f2361809c..68effc391 100644 --- a/website/docs/UserEvent.md +++ b/website/docs/UserEvent.md @@ -242,7 +242,7 @@ User Event will generate a number of intermediate scroll steps to simulate user This function will remember where the last scroll ended, so subsequent scroll interaction will starts from that position. The initial scroll position will be assumed to be `{ y: 0, x: 0 }`. -In order to simulate a `FlatList` (and other controls based on `VirtualizedList`) scrolling, you should pass `contentSize` and `layoutMeasurement` options, which enable the underlying logic to update the currently visible window. +In order to simulate a `FlatList` (and other controls based on `VirtualizedList`) scrolling, you should pass the `contentSize` and `layoutMeasurement` options, which enable the underlying logic to update the currently visible window. ### Sequence of events