diff --git a/src/user-event/index.ts b/src/user-event/index.ts index a94f54be..87c93465 100644 --- a/src/user-event/index.ts +++ b/src/user-event/index.ts @@ -20,4 +20,5 @@ export const userEvent = { paste: (element: ReactTestInstance, text: string) => setup().paste(element, text), scrollTo: (element: ReactTestInstance, options: ScrollToOptions) => setup().scrollTo(element, options), + pullToRefresh: (element: ReactTestInstance) => setup().pullToRefresh(element), }; diff --git a/src/user-event/pull-to-refresh.ts b/src/user-event/pull-to-refresh.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/user-event/scroll/__tests__/pull-to-refresh.test.tsx b/src/user-event/scroll/__tests__/pull-to-refresh.test.tsx new file mode 100644 index 00000000..2d2451b8 --- /dev/null +++ b/src/user-event/scroll/__tests__/pull-to-refresh.test.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { FlatList, RefreshControl, ScrollView, SectionList, Text } from 'react-native'; + +import { render, screen, userEvent } from '../../..'; + +describe('pullToRefresh()', () => { + it('supports ScrollView', async () => { + const onRefreshMock = jest.fn(); + render( + } + />, + ); + const user = userEvent.setup(); + + await user.pullToRefresh(screen.getByTestId('view')); + expect(onRefreshMock).toHaveBeenCalled(); + }); + + it('supports FlatList', async () => { + const onRefreshMock = jest.fn(); + render( + {item}} + refreshControl={} + />, + ); + const user = userEvent.setup(); + + await user.pullToRefresh(screen.getByTestId('view')); + expect(onRefreshMock).toHaveBeenCalled(); + }); + + it('supports SectionList', async () => { + const onRefreshMock = jest.fn(); + render( + {item}} + refreshControl={} + />, + ); + const user = userEvent.setup(); + + await user.pullToRefresh(screen.getByTestId('view')); + expect(onRefreshMock).toHaveBeenCalled(); + }); + + it('does not throw when RefreshControl is not set', async () => { + render(); + const user = userEvent.setup(); + + await expect(() => user.pullToRefresh(screen.getByTestId('view'))).not.toThrow(); + }); + + it('does not throw when RefreshControl onRefresh is not set', async () => { + render(} />); + const user = userEvent.setup(); + + await expect(() => user.pullToRefresh(screen.getByTestId('view'))).not.toThrow(); + }); +}); diff --git a/src/user-event/scroll/pull-to-refresh.ts b/src/user-event/scroll/pull-to-refresh.ts new file mode 100644 index 00000000..3189b32c --- /dev/null +++ b/src/user-event/scroll/pull-to-refresh.ts @@ -0,0 +1,28 @@ +import type { ReactTestInstance } from 'react-test-renderer'; + +import act from '../../act'; +import { ErrorWithStack } from '../../helpers/errors'; +import { isHostScrollView } from '../../helpers/host-component-names'; +import type { UserEventInstance } from '../setup'; + +export async function pullToRefresh( + this: UserEventInstance, + element: ReactTestInstance, +): Promise { + if (!isHostScrollView(element)) { + throw new ErrorWithStack( + `pullToRefresh() works only with host "ScrollView" elements. Passed element has type "${element.type}".`, + pullToRefresh, + ); + } + + const refreshControl = element.props.refreshControl; + if (refreshControl == null || typeof refreshControl.props.onRefresh !== 'function') { + return; + } + + // eslint-disable-next-line require-await + await act(async () => { + refreshControl.props.onRefresh(); + }); +} diff --git a/src/user-event/setup/setup.ts b/src/user-event/setup/setup.ts index e6d164e5..f8105cb5 100644 --- a/src/user-event/setup/setup.ts +++ b/src/user-event/setup/setup.ts @@ -8,6 +8,7 @@ import type { PressOptions } from '../press'; import { longPress, press } from '../press'; import type { ScrollToOptions } from '../scroll'; import { scrollTo } from '../scroll'; +import { pullToRefresh } from '../scroll/pull-to-refresh'; import type { TypeOptions } from '../type'; import { type } from '../type'; import { wait } from '../utils'; @@ -138,12 +139,24 @@ export interface UserEventInstance { paste: (element: ReactTestInstance, text: string) => Promise; /** - * Simlate user scorlling a ScrollView element. + * Simlate user scorlling a given `ScrollView`-like element. * - * @param element ScrollView element + * Supported components: ScrollView, FlatList, SectionList + * + * @param element ScrollView-like element * @returns */ scrollTo: (element: ReactTestInstance, options: ScrollToOptions) => Promise; + + /** + * Simulate using pull-to-refresh gesture on a given `ScrollView`-like element. + * + * Supported components: ScrollView, FlatList, SectionList + * + * @param element ScrollView-like element + * @returns + */ + pullToRefresh: (element: ReactTestInstance) => Promise; } function createInstance(config: UserEventConfig): UserEventInstance { @@ -159,6 +172,7 @@ function createInstance(config: UserEventConfig): UserEventInstance { clear: wrapAndBindImpl(instance, clear), paste: wrapAndBindImpl(instance, paste), scrollTo: wrapAndBindImpl(instance, scrollTo), + pullToRefresh: wrapAndBindImpl(instance, pullToRefresh), }; Object.assign(instance, api);