@testing-library/react-native 12.1.3 → 12.2.1

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.
Files changed (194) hide show
  1. package/.eslintcache +1 -1
  2. package/.eslintignore +1 -0
  3. package/build/fireEvent.js +2 -5
  4. package/build/fireEvent.js.map +1 -1
  5. package/build/helpers/component-tree.d.ts +11 -5
  6. package/build/helpers/component-tree.js +5 -1
  7. package/build/helpers/component-tree.js.map +1 -1
  8. package/build/helpers/deprecation.js +1 -1
  9. package/build/helpers/deprecation.js.map +1 -1
  10. package/build/helpers/findAll.d.ts +2 -1
  11. package/build/helpers/findAll.js +2 -1
  12. package/build/helpers/findAll.js.map +1 -1
  13. package/build/helpers/host-component-names.d.ts +12 -0
  14. package/build/helpers/host-component-names.js +18 -0
  15. package/build/helpers/host-component-names.js.map +1 -1
  16. package/build/helpers/matchers/matchLabelText.js +1 -1
  17. package/build/helpers/matchers/matchLabelText.js.map +1 -1
  18. package/build/pure.d.ts +2 -0
  19. package/build/pure.js +7 -0
  20. package/build/pure.js.map +1 -1
  21. package/build/queries/a11yState.js +1 -1
  22. package/build/queries/a11yState.js.map +1 -1
  23. package/build/queries/a11yValue.js +1 -1
  24. package/build/queries/a11yValue.js.map +1 -1
  25. package/build/queries/displayValue.js +5 -6
  26. package/build/queries/displayValue.js.map +1 -1
  27. package/build/queries/hintText.js +1 -1
  28. package/build/queries/hintText.js.map +1 -1
  29. package/build/queries/labelText.js +1 -1
  30. package/build/queries/labelText.js.map +1 -1
  31. package/build/queries/placeholderText.js +3 -4
  32. package/build/queries/placeholderText.js.map +1 -1
  33. package/build/queries/role.js +1 -1
  34. package/build/queries/role.js.map +1 -1
  35. package/build/queries/testId.js +3 -3
  36. package/build/queries/testId.js.map +1 -1
  37. package/build/queries/text.js +1 -2
  38. package/build/queries/text.js.map +1 -1
  39. package/build/render.js.map +1 -1
  40. package/build/user-event/clear.d.ts +3 -0
  41. package/build/user-event/clear.js +41 -0
  42. package/build/user-event/clear.js.map +1 -0
  43. package/build/user-event/event-builder/common.d.ts +48 -6
  44. package/build/user-event/event-builder/common.js +37 -20
  45. package/build/user-event/event-builder/common.js.map +1 -1
  46. package/build/user-event/event-builder/index.d.ts +94 -0
  47. package/build/user-event/event-builder/index.js +3 -1
  48. package/build/user-event/event-builder/index.js.map +1 -1
  49. package/build/user-event/event-builder/text-input.d.ts +91 -0
  50. package/build/user-event/event-builder/text-input.js +117 -0
  51. package/build/user-event/event-builder/text-input.js.map +1 -0
  52. package/build/user-event/index.d.ts +5 -2
  53. package/build/user-event/index.js +8 -1
  54. package/build/user-event/index.js.map +1 -1
  55. package/build/user-event/press/index.d.ts +1 -1
  56. package/build/user-event/press/index.js +6 -0
  57. package/build/user-event/press/index.js.map +1 -1
  58. package/build/user-event/press/press.d.ts +3 -3
  59. package/build/user-event/press/press.js +54 -64
  60. package/build/user-event/press/press.js.map +1 -1
  61. package/build/user-event/setup/setup.d.ts +45 -3
  62. package/build/user-event/setup/setup.js +17 -2
  63. package/build/user-event/setup/setup.js.map +1 -1
  64. package/build/user-event/type/index.d.ts +1 -1
  65. package/build/user-event/type/index.js +6 -0
  66. package/build/user-event/type/index.js.map +1 -1
  67. package/build/user-event/type/parseKeys.d.ts +1 -0
  68. package/build/user-event/type/parseKeys.js +40 -0
  69. package/build/user-event/type/parseKeys.js.map +1 -0
  70. package/build/user-event/type/type.d.ts +7 -2
  71. package/build/user-event/type/type.js +70 -8
  72. package/build/user-event/type/type.js.map +1 -1
  73. package/build/user-event/utils/content-size.d.ts +15 -0
  74. package/build/user-event/utils/content-size.js +26 -0
  75. package/build/user-event/utils/content-size.js.map +1 -0
  76. package/build/user-event/utils/{events.d.ts → dispatch-event.d.ts} +2 -2
  77. package/build/user-event/utils/dispatch-event.js +36 -0
  78. package/build/user-event/utils/dispatch-event.js.map +1 -0
  79. package/build/user-event/utils/host-components.d.ts +2 -0
  80. package/build/user-event/utils/host-components.js +11 -0
  81. package/build/user-event/utils/host-components.js.map +1 -0
  82. package/build/user-event/utils/index.d.ts +5 -1
  83. package/build/user-event/utils/index.js +48 -4
  84. package/build/user-event/utils/index.js.map +1 -1
  85. package/build/user-event/utils/text-range.d.ts +4 -0
  86. package/build/user-event/utils/text-range.js +2 -0
  87. package/build/user-event/utils/text-range.js.map +1 -0
  88. package/build/user-event/utils/warn-about-real-timers.d.ts +1 -0
  89. package/build/user-event/utils/warn-about-real-timers.js +20 -0
  90. package/build/user-event/utils/warn-about-real-timers.js.map +1 -0
  91. package/examples/basic/.expo/README.md +15 -0
  92. package/examples/basic/.expo/packager-info.json +4 -0
  93. package/examples/basic/.expo/settings.json +10 -0
  94. package/examples/basic/__tests__/App.test.tsx +30 -12
  95. package/examples/basic/package.json +7 -7
  96. package/examples/basic/yarn.lock +7499 -0
  97. package/examples/react-navigation/README.md +2 -0
  98. package/examples/react-navigation/package.json +5 -5
  99. package/examples/react-navigation/yarn.lock +5018 -0
  100. package/examples/redux/README.md +5 -0
  101. package/examples/redux/package.json +7 -7
  102. package/examples/redux/yarn.lock +4819 -0
  103. package/experiments-app/.expo/packager-info.json +2 -2
  104. package/experiments-app/package.json +7 -9
  105. package/experiments-app/src/MainScreen.tsx +1 -0
  106. package/experiments-app/src/experiments.ts +20 -2
  107. package/experiments-app/src/screens/FlatListEvents.tsx +57 -0
  108. package/experiments-app/src/screens/ScrollViewEvents.tsx +65 -0
  109. package/experiments-app/src/screens/SectionListEvents.tsx +91 -0
  110. package/experiments-app/src/screens/TextInputEventPropagation.tsx +5 -17
  111. package/experiments-app/src/screens/TextInputEvents.tsx +13 -15
  112. package/experiments-app/src/utils/helpers.ts +13 -3
  113. package/experiments-app/yarn.lock +901 -1105
  114. package/experiments-rtl/.babelrc +8 -0
  115. package/experiments-rtl/.eslintrc.json +3 -0
  116. package/experiments-rtl/.gitignore +35 -0
  117. package/experiments-rtl/README.md +34 -0
  118. package/experiments-rtl/jest-setup.js +1 -0
  119. package/experiments-rtl/jest.config.js +4 -0
  120. package/experiments-rtl/next.config.js +4 -0
  121. package/experiments-rtl/package.json +38 -0
  122. package/experiments-rtl/postcss.config.js +6 -0
  123. package/experiments-rtl/public/next.svg +1 -0
  124. package/experiments-rtl/public/vercel.svg +1 -0
  125. package/experiments-rtl/src/app/__tests__/click.test.tsx +31 -0
  126. package/experiments-rtl/src/app/__tests__/managed-text-input.test.tsx +51 -0
  127. package/experiments-rtl/src/app/globals.css +27 -0
  128. package/experiments-rtl/src/app/layout.tsx +22 -0
  129. package/experiments-rtl/src/app/page.tsx +113 -0
  130. package/experiments-rtl/tailwind.config.ts +20 -0
  131. package/experiments-rtl/tsconfig.json +28 -0
  132. package/experiments-rtl/yarn.lock +5418 -0
  133. package/package.json +4 -2
  134. package/src/__tests__/act.test.tsx +4 -0
  135. package/src/fireEvent.ts +1 -5
  136. package/src/helpers/component-tree.ts +14 -9
  137. package/src/helpers/deprecation.ts +1 -1
  138. package/src/helpers/findAll.ts +6 -4
  139. package/src/helpers/host-component-names.tsx +21 -0
  140. package/src/helpers/matchers/matchLabelText.ts +0 -1
  141. package/src/pure.ts +2 -0
  142. package/src/queries/a11yState.ts +2 -6
  143. package/src/queries/a11yValue.ts +2 -6
  144. package/src/queries/displayValue.ts +7 -14
  145. package/src/queries/hintText.ts +2 -7
  146. package/src/queries/labelText.ts +1 -3
  147. package/src/queries/placeholderText.ts +6 -13
  148. package/src/queries/role.ts +1 -2
  149. package/src/queries/testId.ts +5 -10
  150. package/src/queries/text.ts +3 -6
  151. package/src/render.tsx +1 -1
  152. package/src/user-event/__tests__/__snapshots__/clear.test.tsx.snap +269 -0
  153. package/src/user-event/__tests__/clear.test.tsx +217 -0
  154. package/src/user-event/clear.ts +59 -0
  155. package/src/user-event/event-builder/common.ts +35 -19
  156. package/src/user-event/event-builder/index.ts +2 -0
  157. package/src/user-event/event-builder/text-input.ts +86 -0
  158. package/src/user-event/index.ts +7 -3
  159. package/src/user-event/press/__tests__/longPress.real-timers.test.tsx +4 -2
  160. package/src/user-event/press/__tests__/press.real-timers.test.tsx +4 -2
  161. package/src/user-event/press/__tests__/press.test.tsx +40 -5
  162. package/src/user-event/press/index.ts +1 -1
  163. package/src/user-event/press/press.ts +93 -64
  164. package/src/user-event/setup/setup.ts +54 -5
  165. package/src/user-event/type/__tests__/__snapshots__/type-managed.test.tsx.snap +339 -0
  166. package/src/user-event/type/__tests__/__snapshots__/type.test.tsx.snap +644 -2
  167. package/src/user-event/type/__tests__/parseKeys.test.ts +23 -0
  168. package/src/user-event/type/__tests__/type-managed.test.tsx +120 -0
  169. package/src/user-event/type/__tests__/type.test.tsx +299 -27
  170. package/src/user-event/type/index.ts +1 -1
  171. package/src/user-event/type/parseKeys.ts +41 -0
  172. package/src/user-event/type/type.ts +128 -10
  173. package/src/user-event/utils/__tests__/dispatch-event.test.tsx +41 -0
  174. package/src/user-event/utils/__tests__/wait.test.ts +0 -1
  175. package/src/user-event/utils/content-size.ts +25 -0
  176. package/src/user-event/utils/dispatch-event.ts +38 -0
  177. package/src/user-event/utils/host-components.ts +6 -0
  178. package/src/user-event/utils/index.ts +5 -1
  179. package/src/user-event/utils/text-range.ts +4 -0
  180. package/src/user-event/{press/utils/warnAboutRealTimers.ts → utils/warn-about-real-timers.ts} +8 -1
  181. package/website/docs/API.md +19 -25
  182. package/website/docs/Queries.md +64 -59
  183. package/website/docs/UserEvent.md +134 -9
  184. package/website/sidebars.js +1 -1
  185. package/build/helpers/filterNodeByType.d.ts +0 -3
  186. package/build/helpers/filterNodeByType.js +0 -9
  187. package/build/helpers/filterNodeByType.js.map +0 -1
  188. package/build/user-event/press/utils/warnAboutRealTimers.d.ts +0 -1
  189. package/build/user-event/press/utils/warnAboutRealTimers.js +0 -14
  190. package/build/user-event/press/utils/warnAboutRealTimers.js.map +0 -1
  191. package/build/user-event/utils/events.js +0 -44
  192. package/build/user-event/utils/events.js.map +0 -1
  193. package/src/helpers/filterNodeByType.ts +0 -7
  194. package/src/user-event/utils/events.ts +0 -54
@@ -1,6 +1,9 @@
1
1
  import { ReactTestInstance } from 'react-test-renderer';
2
2
  import { setup } from './setup';
3
- import { PressOptions } from './press/press';
3
+ import { PressOptions } from './press';
4
+ import { TypeOptions } from './type';
5
+
6
+ export { UserEventConfig } from './setup';
4
7
 
5
8
  export const userEvent = {
6
9
  setup,
@@ -9,6 +12,7 @@ export const userEvent = {
9
12
  press: (element: ReactTestInstance) => setup().press(element),
10
13
  longPress: (element: ReactTestInstance, options?: PressOptions) =>
11
14
  setup().longPress(element, options),
12
- type: (element: ReactTestInstance, text: string) =>
13
- setup().type(element, text),
15
+ type: (element: ReactTestInstance, text: string, options?: TypeOptions) =>
16
+ setup().type(element, text, options),
17
+ clear: (element: ReactTestInstance) => setup().clear(element),
14
18
  };
@@ -2,13 +2,15 @@ import React from 'react';
2
2
  import { Pressable, Text } from 'react-native';
3
3
  import { render, screen } from '../../../pure';
4
4
  import { userEvent } from '../..';
5
- import * as WarnAboutRealTimers from '../utils/warnAboutRealTimers';
5
+ import * as WarnAboutRealTimers from '../../utils/warn-about-real-timers';
6
6
 
7
7
  describe('userEvent.longPress with real timers', () => {
8
8
  beforeEach(() => {
9
9
  jest.useRealTimers();
10
10
  jest.restoreAllMocks();
11
- jest.spyOn(WarnAboutRealTimers, 'warnAboutRealTimers').mockImplementation();
11
+ jest
12
+ .spyOn(WarnAboutRealTimers, 'warnAboutRealTimersIfNeeded')
13
+ .mockImplementation();
12
14
  });
13
15
 
14
16
  test('calls onLongPress if the delayLongPress is the default one', async () => {
@@ -10,13 +10,15 @@ import {
10
10
  import { createEventLogger, getEventsName } from '../../../test-utils';
11
11
  import { render, screen } from '../../..';
12
12
  import { userEvent } from '../..';
13
- import * as WarnAboutRealTimers from '../utils/warnAboutRealTimers';
13
+ import * as WarnAboutRealTimers from '../../utils/warn-about-real-timers';
14
14
 
15
15
  describe('userEvent.press with real timers', () => {
16
16
  beforeEach(() => {
17
17
  jest.useRealTimers();
18
18
  jest.restoreAllMocks();
19
- jest.spyOn(WarnAboutRealTimers, 'warnAboutRealTimers').mockImplementation();
19
+ jest
20
+ .spyOn(WarnAboutRealTimers, 'warnAboutRealTimersIfNeeded')
21
+ .mockImplementation();
20
22
  });
21
23
 
22
24
  test('calls onPressIn, onPress and onPressOut prop of touchable', async () => {
@@ -304,7 +304,7 @@ describe('userEvent.press with fake timers', () => {
304
304
  expect(mockOnPress).toHaveBeenCalled();
305
305
  });
306
306
 
307
- test('works on Text', async () => {
307
+ test('press works on Text', async () => {
308
308
  const { events, logEvent } = createEventLogger();
309
309
 
310
310
  render(
@@ -317,11 +317,29 @@ describe('userEvent.press with fake timers', () => {
317
317
  press me
318
318
  </Text>
319
319
  );
320
- await userEvent.press(screen.getByText('press me'));
321
320
 
321
+ await userEvent.press(screen.getByText('press me'));
322
322
  expect(getEventsName(events)).toEqual(['pressIn', 'press', 'pressOut']);
323
323
  });
324
324
 
325
+ test('longPress works Text', async () => {
326
+ const { events, logEvent } = createEventLogger();
327
+
328
+ render(
329
+ <Text
330
+ onPress={logEvent('press')}
331
+ onPressIn={logEvent('pressIn')}
332
+ onPressOut={logEvent('pressOut')}
333
+ onLongPress={logEvent('longPress')}
334
+ >
335
+ press me
336
+ </Text>
337
+ );
338
+
339
+ await userEvent.longPress(screen.getByText('press me'));
340
+ expect(getEventsName(events)).toEqual(['pressIn', 'longPress', 'pressOut']);
341
+ });
342
+
325
343
  test('doesnt trigger on disabled Text', async () => {
326
344
  const { events, logEvent } = createEventLogger();
327
345
 
@@ -361,7 +379,7 @@ describe('userEvent.press with fake timers', () => {
361
379
  expect(events).toEqual([]);
362
380
  });
363
381
 
364
- test('works on TetInput', async () => {
382
+ test('press works on TextInput', async () => {
365
383
  const { events, logEvent } = createEventLogger();
366
384
 
367
385
  render(
@@ -371,12 +389,27 @@ describe('userEvent.press with fake timers', () => {
371
389
  onPressOut={logEvent('pressOut')}
372
390
  />
373
391
  );
392
+
374
393
  await userEvent.press(screen.getByPlaceholderText('email'));
394
+ expect(getEventsName(events)).toEqual(['pressIn', 'pressOut']);
395
+ });
396
+
397
+ test('longPress works on TextInput', async () => {
398
+ const { events, logEvent } = createEventLogger();
399
+
400
+ render(
401
+ <TextInput
402
+ placeholder="email"
403
+ onPressIn={logEvent('pressIn')}
404
+ onPressOut={logEvent('pressOut')}
405
+ />
406
+ );
375
407
 
408
+ await userEvent.longPress(screen.getByPlaceholderText('email'));
376
409
  expect(getEventsName(events)).toEqual(['pressIn', 'pressOut']);
377
410
  });
378
411
 
379
- test('does not call onPressIn and onPressOut on non editable TetInput', async () => {
412
+ test('does not call onPressIn and onPressOut on non editable TextInput', async () => {
380
413
  const { events, logEvent } = createEventLogger();
381
414
 
382
415
  render(
@@ -387,11 +420,12 @@ describe('userEvent.press with fake timers', () => {
387
420
  onPressOut={logEvent('pressOut')}
388
421
  />
389
422
  );
423
+
390
424
  await userEvent.press(screen.getByPlaceholderText('email'));
391
425
  expect(events).toEqual([]);
392
426
  });
393
427
 
394
- test('does not call onPressIn and onPressOut on TetInput with pointer events disabled', async () => {
428
+ test('does not call onPressIn and onPressOut on TextInput with pointer events disabled', async () => {
395
429
  const { events, logEvent } = createEventLogger();
396
430
 
397
431
  render(
@@ -402,6 +436,7 @@ describe('userEvent.press with fake timers', () => {
402
436
  onPressOut={logEvent('pressOut')}
403
437
  />
404
438
  );
439
+
405
440
  await userEvent.press(screen.getByPlaceholderText('email'));
406
441
  expect(events).toEqual([]);
407
442
  });
@@ -1 +1 @@
1
- export { press, longPress } from './press';
1
+ export { PressOptions, press, longPress } from './press';
@@ -1,50 +1,65 @@
1
1
  import { ReactTestInstance } from 'react-test-renderer';
2
- import { EventBuilder } from '../event-builder';
3
- import { UserEventInstance } from '../setup';
4
- import { wait } from '../utils';
5
2
  import act from '../../act';
6
3
  import { getHostParent } from '../../helpers/component-tree';
7
- import { filterNodeByType } from '../../helpers/filterNodeByType';
8
4
  import { isPointerEventEnabled } from '../../helpers/pointer-events';
9
- import { getHostComponentNames } from '../../helpers/host-component-names';
10
- import { jestFakeTimersAreEnabled } from '../../helpers/timers';
5
+ import { isHostText } from '../../helpers/host-component-names';
6
+ import { EventBuilder } from '../event-builder';
7
+ import { UserEventConfig, UserEventInstance } from '../setup';
8
+ import {
9
+ dispatchEvent,
10
+ isEditableTextInput,
11
+ wait,
12
+ warnAboutRealTimersIfNeeded,
13
+ } from '../utils';
11
14
  import { DEFAULT_MIN_PRESS_DURATION } from './constants';
12
- import { warnAboutRealTimers } from './utils/warnAboutRealTimers';
13
15
 
14
- export type PressOptions = {
15
- duration: number;
16
- };
16
+ export interface PressOptions {
17
+ duration?: number;
18
+ }
17
19
 
18
20
  export async function press(
19
21
  this: UserEventInstance,
20
22
  element: ReactTestInstance
21
23
  ): Promise<void> {
22
- await basePress(this.config, element);
24
+ await basePress(this.config, element, {
25
+ type: 'press',
26
+ duration: 0,
27
+ });
23
28
  }
24
29
 
25
30
  export async function longPress(
26
31
  this: UserEventInstance,
27
32
  element: ReactTestInstance,
28
- options: PressOptions = { duration: 500 }
33
+ options?: PressOptions
29
34
  ): Promise<void> {
30
- await basePress(this.config, element, options);
35
+ await basePress(this.config, element, {
36
+ type: 'longPress',
37
+ duration: options?.duration ?? 500,
38
+ });
39
+ }
40
+
41
+ interface BasePressOptions {
42
+ type: 'press' | 'longPress';
43
+ duration: number;
31
44
  }
32
45
 
33
46
  const basePress = async (
34
- config: UserEventInstance['config'],
47
+ config: UserEventConfig,
35
48
  element: ReactTestInstance,
36
- options: PressOptions = { duration: 0 }
49
+ options: BasePressOptions
37
50
  ): Promise<void> => {
38
- // Text and TextInput components are mocked in React Native preset so the mock
39
- // doesn't implement the pressability class
40
- // Thus we need to call the props directly on the host component
41
- if (isEnabledHostText(element) || isEnabledTextInput(element)) {
42
- await triggerMockPressEvent(config, element, options);
51
+ if (isPressableText(element)) {
52
+ await emitTextPressEvents(config, element, options);
53
+ return;
54
+ }
55
+
56
+ if (isEditableTextInput(element) && isPointerEventEnabled(element)) {
57
+ await emitTextInputPressEvents(config, element, options);
43
58
  return;
44
59
  }
45
60
 
46
61
  if (isEnabledTouchResponder(element)) {
47
- await triggerPressEvent(config, element, options);
62
+ await emitPressablePressEvents(config, element, options);
48
63
  return;
49
64
  }
50
65
 
@@ -56,31 +71,33 @@ const basePress = async (
56
71
  await basePress(config, hostParentElement, options);
57
72
  };
58
73
 
59
- const triggerPressEvent = async (
60
- config: UserEventInstance['config'],
74
+ const emitPressablePressEvents = async (
75
+ config: UserEventConfig,
61
76
  element: ReactTestInstance,
62
- options: PressOptions = { duration: 0 }
77
+ options: BasePressOptions
63
78
  ) => {
64
- const areFakeTimersEnabled = jestFakeTimersAreEnabled();
65
- if (!areFakeTimersEnabled) {
66
- warnAboutRealTimers();
67
- }
79
+ warnAboutRealTimersIfNeeded();
68
80
 
69
81
  await wait(config);
70
82
 
71
83
  await act(async () => {
72
- element.props.onResponderGrant({
73
- ...EventBuilder.Common.touch(),
74
- dispatchConfig: { registrationName: 'onResponderGrant' },
75
- });
84
+ dispatchEvent(
85
+ element,
86
+ 'responderGrant',
87
+ EventBuilder.Common.responderGrant()
88
+ );
76
89
 
77
90
  await wait(config, options.duration);
78
91
 
79
- element.props.onResponderRelease({
80
- ...EventBuilder.Common.touch(),
81
- dispatchConfig: { registrationName: 'onResponderRelease' },
82
- });
92
+ dispatchEvent(
93
+ element,
94
+ 'responderRelease',
95
+ EventBuilder.Common.responderRelease()
96
+ );
83
97
 
98
+ // React Native will wait for minimal delay of DEFAULT_MIN_PRESS_DURATION
99
+ // before emitting the `pressOut` event. We need to wait here, so that
100
+ // `press()` function does not return before that.
84
101
  if (DEFAULT_MIN_PRESS_DURATION - options.duration > 0) {
85
102
  await wait(config, DEFAULT_MIN_PRESS_DURATION - options.duration);
86
103
  }
@@ -94,41 +111,53 @@ const isEnabledTouchResponder = (element: ReactTestInstance) => {
94
111
  );
95
112
  };
96
113
 
97
- const isEnabledHostText = (element: ReactTestInstance) => {
98
- return (
99
- filterNodeByType(element, getHostComponentNames().text) &&
100
- isPointerEventEnabled(element) &&
101
- !element.props.disabled &&
102
- element.props.onPress
114
+ const isPressableText = (element: ReactTestInstance) => {
115
+ const hasPressEventHandler = Boolean(
116
+ element.props.onPress ||
117
+ element.props.onLongPress ||
118
+ element.props.onPressIn ||
119
+ element.props.onPressOut
103
120
  );
104
- };
105
121
 
106
- const isEnabledTextInput = (element: ReactTestInstance) => {
107
122
  return (
108
- filterNodeByType(element, getHostComponentNames().textInput) &&
123
+ isHostText(element) &&
109
124
  isPointerEventEnabled(element) &&
110
- element.props.editable !== false
125
+ !element.props.disabled &&
126
+ hasPressEventHandler
111
127
  );
112
128
  };
113
129
 
114
- const triggerMockPressEvent = async (
115
- config: UserEventInstance['config'],
130
+ /**
131
+ * Dispatches a press event sequence for Text.
132
+ */
133
+ async function emitTextPressEvents(
134
+ config: UserEventConfig,
116
135
  element: ReactTestInstance,
117
- options: PressOptions = { duration: 0 }
118
- ) => {
119
- const { onPressIn, onPress, onPressOut } = element.props;
136
+ options: BasePressOptions
137
+ ) {
120
138
  await wait(config);
121
- if (onPressIn) {
122
- onPressIn(EventBuilder.Common.touch());
123
- }
124
- if (onPress) {
125
- onPress(EventBuilder.Common.touch());
126
- }
139
+ dispatchEvent(element, 'pressIn', EventBuilder.Common.touch());
140
+
141
+ // Emit either `press` or `longPress`.
142
+ dispatchEvent(element, options.type, EventBuilder.Common.touch());
143
+
127
144
  await wait(config, options.duration);
128
- if (onPressOut) {
129
- if (DEFAULT_MIN_PRESS_DURATION - options.duration > 0) {
130
- await wait(config, DEFAULT_MIN_PRESS_DURATION - options.duration);
131
- }
132
- onPressOut(EventBuilder.Common.touch());
133
- }
134
- };
145
+ dispatchEvent(element, 'pressOut', EventBuilder.Common.touch());
146
+ }
147
+
148
+ /**
149
+ * Dispatches a press event sequence for TextInput.
150
+ */
151
+ async function emitTextInputPressEvents(
152
+ config: UserEventConfig,
153
+ element: ReactTestInstance,
154
+ options: BasePressOptions
155
+ ) {
156
+ await wait(config);
157
+ dispatchEvent(element, 'pressIn', EventBuilder.Common.touch());
158
+
159
+ // Note: TextInput does not have `onPress`/`onLongPress` props.
160
+
161
+ await wait(config, options.duration);
162
+ dispatchEvent(element, 'pressOut', EventBuilder.Common.touch());
163
+ }
@@ -1,8 +1,8 @@
1
1
  import { ReactTestInstance } from 'react-test-renderer';
2
2
  import { jestFakeTimersAreEnabled } from '../../helpers/timers';
3
- import { press, longPress } from '../press';
4
- import { type } from '../type';
5
- import { PressOptions } from '../press/press';
3
+ import { PressOptions, press, longPress } from '../press';
4
+ import { TypeOptions, type } from '../type';
5
+ import { clear } from '../clear';
6
6
 
7
7
  export interface UserEventSetupOptions {
8
8
  /**
@@ -46,7 +46,7 @@ const defaultOptions: Required<UserEventSetupOptions> = {
46
46
  * Creates a new instance of user event instance with the given options.
47
47
  *
48
48
  * @param options
49
- * @returns
49
+ * @returns UserEvent instance
50
50
  */
51
51
  export function setup(options?: UserEventSetupOptions) {
52
52
  const config = createConfig(options);
@@ -54,6 +54,12 @@ export function setup(options?: UserEventSetupOptions) {
54
54
  return instance;
55
55
  }
56
56
 
57
+ /**
58
+ * Options affecting all user event interactions.
59
+ *
60
+ * @param delay between some subsequent inputs like typing a series of characters
61
+ * @param advanceTimers function to be called to advance fake timers
62
+ */
57
63
  export interface UserEventConfig {
58
64
  delay: number;
59
65
  advanceTimers: (delay: number) => Promise<void> | void;
@@ -66,14 +72,56 @@ function createConfig(options?: UserEventSetupOptions): UserEventConfig {
66
72
  };
67
73
  }
68
74
 
75
+ /**
76
+ * UserEvent instance used to invoke user interaction functions.
77
+ */
69
78
  export interface UserEventInstance {
70
79
  config: UserEventConfig;
80
+
71
81
  press: (element: ReactTestInstance) => Promise<void>;
72
82
  longPress: (
73
83
  element: ReactTestInstance,
74
84
  options?: PressOptions
75
85
  ) => Promise<void>;
76
- type: (element: ReactTestInstance, text: string) => Promise<void>;
86
+
87
+ /**
88
+ * Simulate user pressing on a given `TextInput` element and typing given text.
89
+ *
90
+ * This method will trigger the events for each character of the text:
91
+ * `keyPress`, `change`, `changeText`, `endEditing`, etc.
92
+ *
93
+ * It will also trigger events connected with entering and leaving the text
94
+ * input.
95
+ *
96
+ * The exact events sent depend on the props of the TextInput (`editable`,
97
+ * `multiline`, value, defaultValue, etc) and passed options.
98
+ *
99
+ * @param element TextInput element to type on
100
+ * @param text Text to type
101
+ * @param options Options affecting typing behavior:
102
+ * - `skipPress` - if true, `pressIn` and `pressOut` events will not be
103
+ * triggered.
104
+ * - `submitEditing` - if true, `submitEditing` event will be triggered after
105
+ * typing the text.
106
+ */
107
+ type: (
108
+ element: ReactTestInstance,
109
+ text: string,
110
+ options?: TypeOptions
111
+ ) => Promise<void>;
112
+
113
+ /**
114
+ * Simulate user clearing the text of a given `TextInput` element.
115
+ *
116
+ * This method will simulate:
117
+ * 1. entering TextInput
118
+ * 2. selecting all text
119
+ * 3. pressing backspace to delete all text
120
+ * 4. leaving TextInput
121
+ *
122
+ * @param element TextInput element to clear
123
+ */
124
+ clear: (element: ReactTestInstance) => Promise<void>;
77
125
  }
78
126
 
79
127
  function createInstance(config: UserEventConfig): UserEventInstance {
@@ -86,6 +134,7 @@ function createInstance(config: UserEventConfig): UserEventInstance {
86
134
  press: press.bind(instance),
87
135
  longPress: longPress.bind(instance),
88
136
  type: type.bind(instance),
137
+ clear: clear.bind(instance),
89
138
  };
90
139
 
91
140
  Object.assign(instance, api);