Skip to content

Commit 22c25be

Browse files
committed
feat: User Event pullToRefresh()
1 parent 62b5dfd commit 22c25be

File tree

5 files changed

+100
-2
lines changed

5 files changed

+100
-2
lines changed

src/user-event/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ export const userEvent = {
2020
paste: (element: ReactTestInstance, text: string) => setup().paste(element, text),
2121
scrollTo: (element: ReactTestInstance, options: ScrollToOptions) =>
2222
setup().scrollTo(element, options),
23+
pullToRefresh: (element: ReactTestInstance) => setup().pullToRefresh(element),
2324
};

src/user-event/pull-to-refresh.ts

Whitespace-only changes.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as React from 'react';
2+
import { FlatList, RefreshControl, ScrollView, SectionList, Text } from 'react-native';
3+
4+
import { render, screen, userEvent } from '../../..';
5+
6+
describe('pullToRefresh()', () => {
7+
it('supports ScrollView', async () => {
8+
const onRefreshMock = jest.fn();
9+
render(
10+
<ScrollView
11+
testID="view"
12+
refreshControl={<RefreshControl refreshing={false} onRefresh={onRefreshMock} />}
13+
/>,
14+
);
15+
const user = userEvent.setup();
16+
17+
await user.pullToRefresh(screen.getByTestId('view'));
18+
expect(onRefreshMock).toHaveBeenCalled();
19+
});
20+
21+
it('supports FlatList', async () => {
22+
const onRefreshMock = jest.fn();
23+
render(
24+
<FlatList
25+
testID="view"
26+
data={['A', 'B', 'C']}
27+
renderItem={({ item }) => <Text>{item}</Text>}
28+
refreshControl={<RefreshControl refreshing={false} onRefresh={onRefreshMock} />}
29+
/>,
30+
);
31+
const user = userEvent.setup();
32+
33+
await user.pullToRefresh(screen.getByTestId('view'));
34+
expect(onRefreshMock).toHaveBeenCalled();
35+
});
36+
37+
it('supports SectionList', async () => {
38+
const onRefreshMock = jest.fn();
39+
render(
40+
<SectionList
41+
testID="view"
42+
sections={[
43+
{ title: 'Section 1', data: ['A', 'B', 'C'] },
44+
{ title: 'Section 2', data: ['D', 'E', 'F'] },
45+
]}
46+
renderItem={({ item }) => <Text>{item}</Text>}
47+
refreshControl={<RefreshControl refreshing={false} onRefresh={onRefreshMock} />}
48+
/>,
49+
);
50+
const user = userEvent.setup();
51+
52+
await user.pullToRefresh(screen.getByTestId('view'));
53+
expect(onRefreshMock).toHaveBeenCalled();
54+
});
55+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { ReactTestInstance } from 'react-test-renderer';
2+
3+
import act from '../../act';
4+
import { ErrorWithStack } from '../../helpers/errors';
5+
import { isHostScrollView } from '../../helpers/host-component-names';
6+
import type { UserEventInstance } from '../setup';
7+
8+
export async function pullToRefresh(
9+
this: UserEventInstance,
10+
element: ReactTestInstance,
11+
): Promise<void> {
12+
if (!isHostScrollView(element)) {
13+
throw new ErrorWithStack(
14+
`pullToRefresh() works only with host "ScrollView" elements. Passed element has type "${element.type}".`,
15+
pullToRefresh,
16+
);
17+
}
18+
19+
const refreshControl = element.props.refreshControl;
20+
if (refreshControl == null || typeof refreshControl.props.onRefresh !== 'function') {
21+
return;
22+
}
23+
24+
// eslint-disable-next-line require-await
25+
await act(async () => {
26+
refreshControl.props.onRefresh();
27+
});
28+
}

src/user-event/setup/setup.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { scrollTo } from '../scroll';
1111
import type { TypeOptions } from '../type';
1212
import { type } from '../type';
1313
import { wait } from '../utils';
14+
import { pullToRefresh } from '../scroll/pull-to-refresh';
1415

1516
export interface UserEventSetupOptions {
1617
/**
@@ -138,12 +139,24 @@ export interface UserEventInstance {
138139
paste: (element: ReactTestInstance, text: string) => Promise<void>;
139140

140141
/**
141-
* Simlate user scorlling a ScrollView element.
142+
* Simlate user scorlling a given `ScrollView`-like element.
142143
*
143-
* @param element ScrollView element
144+
* Supported components: ScrollView, FlatList, SectionList
145+
*
146+
* @param element ScrollView-like element
144147
* @returns
145148
*/
146149
scrollTo: (element: ReactTestInstance, options: ScrollToOptions) => Promise<void>;
150+
151+
/**
152+
* Simulate using pull-to-refresh gesture on a given `ScrollView`-like element.
153+
*
154+
* Supported components: ScrollView, FlatList, SectionList
155+
*
156+
* @param element ScrollView-like element
157+
* @returns
158+
*/
159+
pullToRefresh: (element: ReactTestInstance) => Promise<void>;
147160
}
148161

149162
function createInstance(config: UserEventConfig): UserEventInstance {
@@ -159,6 +172,7 @@ function createInstance(config: UserEventConfig): UserEventInstance {
159172
clear: wrapAndBindImpl(instance, clear),
160173
paste: wrapAndBindImpl(instance, paste),
161174
scrollTo: wrapAndBindImpl(instance, scrollTo),
175+
pullToRefresh: wrapAndBindImpl(instance, pullToRefresh),
162176
};
163177

164178
Object.assign(instance, api);

0 commit comments

Comments
 (0)