@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
@@ -0,0 +1,269 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`clear() supports basic case: value: "Hello! 1`] = `
4
+ [
5
+ {
6
+ "name": "focus",
7
+ "payload": {
8
+ "nativeEvent": {
9
+ "target": 0,
10
+ },
11
+ },
12
+ },
13
+ {
14
+ "name": "selectionChange",
15
+ "payload": {
16
+ "nativeEvent": {
17
+ "selection": {
18
+ "end": 6,
19
+ "start": 0,
20
+ },
21
+ },
22
+ },
23
+ },
24
+ {
25
+ "name": "keyPress",
26
+ "payload": {
27
+ "nativeEvent": {
28
+ "key": "Backspace",
29
+ },
30
+ },
31
+ },
32
+ {
33
+ "name": "change",
34
+ "payload": {
35
+ "nativeEvent": {
36
+ "eventCount": 0,
37
+ "target": 0,
38
+ "text": "",
39
+ },
40
+ },
41
+ },
42
+ {
43
+ "name": "changeText",
44
+ "payload": "",
45
+ },
46
+ {
47
+ "name": "selectionChange",
48
+ "payload": {
49
+ "nativeEvent": {
50
+ "selection": {
51
+ "end": 0,
52
+ "start": 0,
53
+ },
54
+ },
55
+ },
56
+ },
57
+ {
58
+ "name": "endEditing",
59
+ "payload": {
60
+ "nativeEvent": {
61
+ "target": 0,
62
+ "text": "",
63
+ },
64
+ },
65
+ },
66
+ {
67
+ "name": "blur",
68
+ "payload": {
69
+ "nativeEvent": {
70
+ "target": 0,
71
+ },
72
+ },
73
+ },
74
+ ]
75
+ `;
76
+
77
+ exports[`clear() supports defaultValue prop: defaultValue: "Hello Default!" 1`] = `
78
+ [
79
+ {
80
+ "name": "focus",
81
+ "payload": {
82
+ "nativeEvent": {
83
+ "target": 0,
84
+ },
85
+ },
86
+ },
87
+ {
88
+ "name": "selectionChange",
89
+ "payload": {
90
+ "nativeEvent": {
91
+ "selection": {
92
+ "end": 14,
93
+ "start": 0,
94
+ },
95
+ },
96
+ },
97
+ },
98
+ {
99
+ "name": "keyPress",
100
+ "payload": {
101
+ "nativeEvent": {
102
+ "key": "Backspace",
103
+ },
104
+ },
105
+ },
106
+ {
107
+ "name": "change",
108
+ "payload": {
109
+ "nativeEvent": {
110
+ "eventCount": 0,
111
+ "target": 0,
112
+ "text": "",
113
+ },
114
+ },
115
+ },
116
+ {
117
+ "name": "changeText",
118
+ "payload": "",
119
+ },
120
+ {
121
+ "name": "selectionChange",
122
+ "payload": {
123
+ "nativeEvent": {
124
+ "selection": {
125
+ "end": 0,
126
+ "start": 0,
127
+ },
128
+ },
129
+ },
130
+ },
131
+ {
132
+ "name": "endEditing",
133
+ "payload": {
134
+ "nativeEvent": {
135
+ "target": 0,
136
+ "text": "",
137
+ },
138
+ },
139
+ },
140
+ {
141
+ "name": "blur",
142
+ "payload": {
143
+ "nativeEvent": {
144
+ "target": 0,
145
+ },
146
+ },
147
+ },
148
+ ]
149
+ `;
150
+
151
+ exports[`clear() supports multiline: value: "Hello World!
152
+ How are you?" multiline: true, 1`] = `
153
+ [
154
+ {
155
+ "name": "focus",
156
+ "payload": {
157
+ "nativeEvent": {
158
+ "target": 0,
159
+ },
160
+ },
161
+ },
162
+ {
163
+ "name": "selectionChange",
164
+ "payload": {
165
+ "nativeEvent": {
166
+ "selection": {
167
+ "end": 25,
168
+ "start": 0,
169
+ },
170
+ },
171
+ },
172
+ },
173
+ {
174
+ "name": "keyPress",
175
+ "payload": {
176
+ "nativeEvent": {
177
+ "key": "Backspace",
178
+ },
179
+ },
180
+ },
181
+ {
182
+ "name": "textInput",
183
+ "payload": {
184
+ "nativeEvent": {
185
+ "previousText": "Hello World!
186
+ How are you?",
187
+ "range": {
188
+ "end": 0,
189
+ "start": 0,
190
+ },
191
+ "target": 0,
192
+ "text": "",
193
+ },
194
+ },
195
+ },
196
+ {
197
+ "name": "change",
198
+ "payload": {
199
+ "nativeEvent": {
200
+ "eventCount": 0,
201
+ "target": 0,
202
+ "text": "",
203
+ },
204
+ },
205
+ },
206
+ {
207
+ "name": "changeText",
208
+ "payload": "",
209
+ },
210
+ {
211
+ "name": "selectionChange",
212
+ "payload": {
213
+ "nativeEvent": {
214
+ "selection": {
215
+ "end": 0,
216
+ "start": 0,
217
+ },
218
+ },
219
+ },
220
+ },
221
+ {
222
+ "name": "contentSizeChange",
223
+ "payload": {
224
+ "nativeEvent": {
225
+ "contentSize": {
226
+ "height": 16,
227
+ "width": 0,
228
+ },
229
+ "target": 0,
230
+ },
231
+ },
232
+ },
233
+ {
234
+ "name": "endEditing",
235
+ "payload": {
236
+ "nativeEvent": {
237
+ "target": 0,
238
+ "text": "",
239
+ },
240
+ },
241
+ },
242
+ {
243
+ "name": "blur",
244
+ "payload": {
245
+ "nativeEvent": {
246
+ "target": 0,
247
+ },
248
+ },
249
+ },
250
+ ]
251
+ `;
252
+
253
+ exports[`clear() works when not all events have handlers 1`] = `
254
+ [
255
+ {
256
+ "name": "changeText",
257
+ "payload": "",
258
+ },
259
+ {
260
+ "name": "endEditing",
261
+ "payload": {
262
+ "nativeEvent": {
263
+ "target": 0,
264
+ "text": "",
265
+ },
266
+ },
267
+ },
268
+ ]
269
+ `;
@@ -0,0 +1,217 @@
1
+ import * as React from 'react';
2
+ import { View, TextInput, TextInputProps } from 'react-native';
3
+ import { createEventLogger } from '../../test-utils/events';
4
+ import { render, userEvent } from '../..';
5
+
6
+ beforeEach(() => {
7
+ jest.useRealTimers();
8
+ });
9
+
10
+ function renderTextInputWithToolkit(props: TextInputProps = {}) {
11
+ const { events, logEvent } = createEventLogger();
12
+
13
+ const screen = render(
14
+ <TextInput
15
+ testID="input"
16
+ onFocus={logEvent('focus')}
17
+ onBlur={logEvent('blur')}
18
+ onPressIn={logEvent('pressIn')}
19
+ onPressOut={logEvent('pressOut')}
20
+ onChange={logEvent('change')}
21
+ onChangeText={logEvent('changeText')}
22
+ onKeyPress={logEvent('keyPress')}
23
+ onTextInput={logEvent('textInput')}
24
+ onSelectionChange={logEvent('selectionChange')}
25
+ onSubmitEditing={logEvent('submitEditing')}
26
+ onEndEditing={logEvent('endEditing')}
27
+ onContentSizeChange={logEvent('contentSizeChange')}
28
+ {...props}
29
+ />
30
+ );
31
+
32
+ const textInput = screen.getByTestId('input');
33
+
34
+ return {
35
+ events,
36
+ textInput,
37
+ };
38
+ }
39
+
40
+ describe('clear()', () => {
41
+ it('supports basic case', async () => {
42
+ jest.spyOn(Date, 'now').mockImplementation(() => 100100100100);
43
+ const { textInput, events } = renderTextInputWithToolkit({
44
+ value: 'Hello!',
45
+ });
46
+
47
+ const user = userEvent.setup();
48
+ await user.clear(textInput);
49
+
50
+ const eventNames = events.map((e) => e.name);
51
+ expect(eventNames).toEqual([
52
+ 'focus',
53
+ 'selectionChange',
54
+ 'keyPress',
55
+ 'change',
56
+ 'changeText',
57
+ 'selectionChange',
58
+ 'endEditing',
59
+ 'blur',
60
+ ]);
61
+
62
+ expect(events).toMatchSnapshot('value: "Hello!');
63
+ });
64
+
65
+ it.each(['modern', 'legacy'])('works with %s fake timers', async (type) => {
66
+ jest.useFakeTimers({ legacyFakeTimers: type === 'legacy' });
67
+ const { textInput, events } = renderTextInputWithToolkit({
68
+ value: 'Hello!',
69
+ });
70
+
71
+ const user = userEvent.setup();
72
+ await user.clear(textInput);
73
+
74
+ const eventNames = events.map((e) => e.name);
75
+ expect(eventNames).toEqual([
76
+ 'focus',
77
+ 'selectionChange',
78
+ 'keyPress',
79
+ 'change',
80
+ 'changeText',
81
+ 'selectionChange',
82
+ 'endEditing',
83
+ 'blur',
84
+ ]);
85
+ });
86
+
87
+ it('supports defaultValue prop', async () => {
88
+ const { textInput, events } = renderTextInputWithToolkit({
89
+ defaultValue: 'Hello Default!',
90
+ });
91
+
92
+ const user = userEvent.setup();
93
+ await user.clear(textInput);
94
+
95
+ const eventNames = events.map((e) => e.name);
96
+ expect(eventNames).toEqual([
97
+ 'focus',
98
+ 'selectionChange',
99
+ 'keyPress',
100
+ 'change',
101
+ 'changeText',
102
+ 'selectionChange',
103
+ 'endEditing',
104
+ 'blur',
105
+ ]);
106
+
107
+ expect(events).toMatchSnapshot('defaultValue: "Hello Default!"');
108
+ });
109
+
110
+ it('does respect editable prop', async () => {
111
+ const { textInput } = renderTextInputWithToolkit({
112
+ value: 'Hello!',
113
+ editable: false,
114
+ });
115
+
116
+ const user = userEvent.setup();
117
+ user.clear(textInput);
118
+
119
+ expect(textInput.props.value).toBe('Hello!');
120
+ });
121
+
122
+ it('does respect pointer-events prop', async () => {
123
+ const { textInput } = renderTextInputWithToolkit({
124
+ value: 'Hello!',
125
+ pointerEvents: 'none',
126
+ });
127
+
128
+ const user = userEvent.setup();
129
+ user.clear(textInput);
130
+
131
+ expect(textInput.props.value).toBe('Hello!');
132
+ });
133
+
134
+ it('supports multiline', async () => {
135
+ const { textInput, events } = renderTextInputWithToolkit({
136
+ value: 'Hello World!\nHow are you?',
137
+ multiline: true,
138
+ });
139
+
140
+ const user = userEvent.setup();
141
+ await user.clear(textInput);
142
+
143
+ const eventNames = events.map((e) => e.name);
144
+ expect(eventNames).toEqual([
145
+ 'focus',
146
+ 'selectionChange',
147
+ 'keyPress',
148
+ 'textInput',
149
+ 'change',
150
+ 'changeText',
151
+ 'selectionChange',
152
+ 'contentSizeChange',
153
+ 'endEditing',
154
+ 'blur',
155
+ ]);
156
+
157
+ expect(events).toMatchSnapshot(
158
+ 'value: "Hello World!\nHow are you?" multiline: true,'
159
+ );
160
+ });
161
+
162
+ it('works when not all events have handlers', async () => {
163
+ const { events, logEvent } = createEventLogger();
164
+ const screen = render(
165
+ <TextInput
166
+ testID="input"
167
+ onChangeText={logEvent('changeText')}
168
+ onEndEditing={logEvent('endEditing')}
169
+ />
170
+ );
171
+
172
+ const user = userEvent.setup();
173
+ await user.clear(screen.getByTestId('input'));
174
+
175
+ const eventNames = events.map((e) => e.name);
176
+ expect(eventNames).toEqual(['changeText', 'endEditing']);
177
+
178
+ expect(events).toMatchSnapshot();
179
+ });
180
+
181
+ it('does NOT work on View', async () => {
182
+ const screen = render(<View testID="input" />);
183
+
184
+ const user = userEvent.setup();
185
+ await expect(
186
+ user.clear(screen.getByTestId('input'))
187
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
188
+ `"clear() only supports host "TextInput" elements. Passed element has type: "View"."`
189
+ );
190
+ });
191
+
192
+ // View that ignores props type checking
193
+ const AnyView = View as React.ComponentType<any>;
194
+
195
+ it('does NOT bubble up', async () => {
196
+ const parentHandler = jest.fn();
197
+ const screen = render(
198
+ <AnyView
199
+ onChangeText={parentHandler}
200
+ onChange={parentHandler}
201
+ onKeyPress={parentHandler}
202
+ onTextInput={parentHandler}
203
+ onFocus={parentHandler}
204
+ onBlur={parentHandler}
205
+ onEndEditing={parentHandler}
206
+ onPressIn={parentHandler}
207
+ onPressOut={parentHandler}
208
+ >
209
+ <TextInput testID="input" />
210
+ </AnyView>
211
+ );
212
+
213
+ const user = userEvent.setup();
214
+ await user.clear(screen.getByTestId('input'));
215
+ expect(parentHandler).not.toHaveBeenCalled();
216
+ });
217
+ });
@@ -0,0 +1,59 @@
1
+ import { ReactTestInstance } from 'react-test-renderer';
2
+ import { ErrorWithStack } from '../helpers/errors';
3
+ import { isHostTextInput } from '../helpers/host-component-names';
4
+ import { isPointerEventEnabled } from '../helpers/pointer-events';
5
+ import { EventBuilder } from './event-builder';
6
+ import { UserEventInstance } from './setup';
7
+ import { dispatchEvent, wait, isEditableTextInput } from './utils';
8
+ import { emitTypingEvents } from './type/type';
9
+
10
+ export async function clear(
11
+ this: UserEventInstance,
12
+ element: ReactTestInstance
13
+ ): Promise<void> {
14
+ if (!isHostTextInput(element)) {
15
+ throw new ErrorWithStack(
16
+ `clear() only supports host "TextInput" elements. Passed element has type: "${element.type}".`,
17
+ clear
18
+ );
19
+ }
20
+
21
+ if (!isEditableTextInput(element) || !isPointerEventEnabled(element)) {
22
+ return;
23
+ }
24
+
25
+ // 1. Enter element
26
+ dispatchEvent(element, 'focus', EventBuilder.Common.focus());
27
+
28
+ // 2. Select all
29
+ const previousText = element.props.value ?? element.props.defaultValue ?? '';
30
+ const selectionRange = {
31
+ start: 0,
32
+ end: previousText.length,
33
+ };
34
+ dispatchEvent(
35
+ element,
36
+ 'selectionChange',
37
+ EventBuilder.TextInput.selectionChange(selectionRange)
38
+ );
39
+
40
+ // 3. Press backspace
41
+ const finalText = '';
42
+ await emitTypingEvents(
43
+ this.config,
44
+ element,
45
+ 'Backspace',
46
+ finalText,
47
+ previousText
48
+ );
49
+
50
+ // 4. Exit element
51
+ await wait(this.config);
52
+ dispatchEvent(
53
+ element,
54
+ 'endEditing',
55
+ EventBuilder.TextInput.endEditing(finalText)
56
+ );
57
+
58
+ dispatchEvent(element, 'blur', EventBuilder.Common.blur());
59
+ }
@@ -1,24 +1,40 @@
1
+ /**
2
+ * Experimental values:
3
+ * - iOS: `{"changedTouches": [[Circular]], "identifier": 1, "locationX": 253, "locationY": 30.333328247070312, "pageX": 273, "pageY": 141.3333282470703, "target": 75, "timestamp": 875928682.0450834, "touches": [[Circular]]}`
4
+ * - Android: `{"changedTouches": [[Circular]], "identifier": 0, "locationX": 160, "locationY": 40.3636360168457, "pageX": 180, "pageY": 140.36363220214844, "target": 53, "targetSurface": -1, "timestamp": 10290805, "touches": [[Circular]]}`
5
+ */
6
+ function touch() {
7
+ return {
8
+ persist: jest.fn(),
9
+ currentTarget: { measure: jest.fn() },
10
+ nativeEvent: {
11
+ changedTouches: [],
12
+ identifier: 0,
13
+ locationX: 0,
14
+ locationY: 0,
15
+ pageX: 0,
16
+ pageY: 0,
17
+ target: 0,
18
+ timestamp: Date.now(),
19
+ touches: [],
20
+ },
21
+ };
22
+ }
23
+
1
24
  export const CommonEventBuilder = {
2
- /**
3
- * Experimental values:
4
- * - iOS: `{"changedTouches": [[Circular]], "identifier": 1, "locationX": 253, "locationY": 30.333328247070312, "pageX": 273, "pageY": 141.3333282470703, "target": 75, "timestamp": 875928682.0450834, "touches": [[Circular]]}`
5
- * - Android: `{"changedTouches": [[Circular]], "identifier": 0, "locationX": 160, "locationY": 40.3636360168457, "pageX": 180, "pageY": 140.36363220214844, "target": 53, "targetSurface": -1, "timestamp": 10290805, "touches": [[Circular]]}`
6
- */
7
- touch: () => {
25
+ touch,
26
+
27
+ responderGrant: () => {
8
28
  return {
9
- persist: jest.fn(),
10
- currentTarget: { measure: jest.fn() },
11
- nativeEvent: {
12
- changedTouches: [],
13
- identifier: 0,
14
- locationX: 0,
15
- locationY: 0,
16
- pageX: 0,
17
- pageY: 0,
18
- target: 0,
19
- timestamp: Date.now(),
20
- touches: [],
21
- },
29
+ ...touch(),
30
+ dispatchConfig: { registrationName: 'onResponderGrant' },
31
+ };
32
+ },
33
+
34
+ responderRelease: () => {
35
+ return {
36
+ ...touch(),
37
+ dispatchConfig: { registrationName: 'onResponderRelease' },
22
38
  };
23
39
  },
24
40
 
@@ -1,5 +1,7 @@
1
1
  import { CommonEventBuilder } from './common';
2
+ import { TextInputEventBuilder } from './text-input';
2
3
 
3
4
  export const EventBuilder = {
4
5
  Common: CommonEventBuilder,
6
+ TextInput: TextInputEventBuilder,
5
7
  };
@@ -0,0 +1,86 @@
1
+ import { ContentSize } from '../utils/content-size';
2
+ import { TextRange } from '../utils/text-range';
3
+
4
+ export const TextInputEventBuilder = {
5
+ /**
6
+ * Experimental values:
7
+ * - iOS: `{"eventCount": 4, "target": 75, "text": "Test"}`
8
+ * - Android: `{"eventCount": 6, "target": 53, "text": "Tes"}`
9
+ */
10
+ change: (text: string) => {
11
+ return {
12
+ nativeEvent: { text, target: 0, eventCount: 0 },
13
+ };
14
+ },
15
+
16
+ /**
17
+ * Experimental values:
18
+ * - iOS: `{"eventCount": 3, "key": "a", "target": 75}`
19
+ * - Android: `{"key": "a"}`
20
+ */
21
+ keyPress: (key: string) => {
22
+ return {
23
+ nativeEvent: { key },
24
+ };
25
+ },
26
+
27
+ /**
28
+ * Experimental values:
29
+ * - iOS: `{"eventCount": 4, "target": 75, "text": "Test"}`
30
+ * - Android: `{"target": 53, "text": "Test"}`
31
+ */
32
+ submitEditing: (text: string) => {
33
+ return {
34
+ nativeEvent: { text, target: 0 },
35
+ };
36
+ },
37
+
38
+ /**
39
+ * Experimental values:
40
+ * - iOS: `{"eventCount": 4, "target": 75, "text": "Test"}`
41
+ * - Android: `{"target": 53, "text": "Test"}`
42
+ */
43
+ endEditing: (text: string) => {
44
+ return {
45
+ nativeEvent: { text, target: 0 },
46
+ };
47
+ },
48
+
49
+ /**
50
+ * Experimental values:
51
+ * - iOS: `{"selection": {"end": 4, "start": 4}, "target": 75}`
52
+ * - Android: `{"selection": {"end": 4, "start": 4}}`
53
+ */
54
+ selectionChange: ({ start, end }: TextRange) => {
55
+ return {
56
+ nativeEvent: { selection: { start, end } },
57
+ };
58
+ },
59
+
60
+ /**
61
+ * Experimental values:
62
+ * - iOS: `{"eventCount": 2, "previousText": "Te", "range": {"end": 2, "start": 2}, "target": 75, "text": "s"}`
63
+ * - Android: `{"previousText": "Te", "range": {"end": 2, "start": 0}, "target": 53, "text": "Tes"}`
64
+ */
65
+ textInput: (text: string, previousText: string) => {
66
+ return {
67
+ nativeEvent: {
68
+ text,
69
+ previousText,
70
+ range: { start: text.length, end: text.length },
71
+ target: 0,
72
+ },
73
+ };
74
+ },
75
+
76
+ /**
77
+ * Experimental values:
78
+ * - iOS: `{"contentSize": {"height": 21.666666666666668, "width": 11.666666666666666}, "target": 75}`
79
+ * - Android: `{"contentSize": {"height": 61.45454406738281, "width": 352.7272644042969}, "target": 53}`
80
+ */
81
+ contentSizeChange: ({ width, height }: ContentSize) => {
82
+ return {
83
+ nativeEvent: { contentSize: { width, height }, target: 0 },
84
+ };
85
+ },
86
+ };