@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 +1 @@
1
- {"version":3,"file":"setup.js","names":["_timers","require","_press","_type","universalJestAdvanceTimersBy","ms","jestFakeTimersAreEnabled","jest","advanceTimersByTime","Promise","resolve","defaultOptions","delay","advanceTimers","setup","options","config","createConfig","instance","createInstance","api","press","bind","longPress","type","Object","assign"],"sources":["../../../src/user-event/setup/setup.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport { jestFakeTimersAreEnabled } from '../../helpers/timers';\nimport { press, longPress } from '../press';\nimport { type } from '../type';\nimport { PressOptions } from '../press/press';\n\nexport interface UserEventSetupOptions {\n /**\n * Between some subsequent inputs like typing a series of characters\n * the code execution is delayed per `setTimeout` for (at least) `delay` seconds.\n * This moves the next changes at least to next macro task\n * and allows other (asynchronous) code to run between events.\n *\n * `null` prevents `setTimeout` from being called.\n *\n * @default 0\n */\n delay?: number;\n\n /**\n * Function to be called to advance fake timers. Setting it is necessary for\n * fake timers to work.\n *\n * @example jest.advanceTimersByTime\n */\n advanceTimers?: (delay: number) => Promise<void> | void;\n}\n\n/**\n * This functions allow wait to work correctly under both real and fake Jest timers.\n */\nfunction universalJestAdvanceTimersBy(ms: number) {\n if (jestFakeTimersAreEnabled()) {\n return jest.advanceTimersByTime(ms);\n } else {\n return Promise.resolve();\n }\n}\n\nconst defaultOptions: Required<UserEventSetupOptions> = {\n delay: 0,\n advanceTimers: universalJestAdvanceTimersBy,\n};\n\n/**\n * Creates a new instance of user event instance with the given options.\n *\n * @param options\n * @returns\n */\nexport function setup(options?: UserEventSetupOptions) {\n const config = createConfig(options);\n const instance = createInstance(config);\n return instance;\n}\n\nexport interface UserEventConfig {\n delay: number;\n advanceTimers: (delay: number) => Promise<void> | void;\n}\n\nfunction createConfig(options?: UserEventSetupOptions): UserEventConfig {\n return {\n ...defaultOptions,\n ...options,\n };\n}\n\nexport interface UserEventInstance {\n config: UserEventConfig;\n press: (element: ReactTestInstance) => Promise<void>;\n longPress: (\n element: ReactTestInstance,\n options?: PressOptions\n ) => Promise<void>;\n type: (element: ReactTestInstance, text: string) => Promise<void>;\n}\n\nfunction createInstance(config: UserEventConfig): UserEventInstance {\n const instance = {\n config,\n } as UserEventInstance;\n\n // We need to bind these functions, as they access the config through 'this.config'.\n const api = {\n press: press.bind(instance),\n longPress: longPress.bind(instance),\n type: type.bind(instance),\n };\n\n Object.assign(instance, api);\n return instance;\n}\n"],"mappings":";;;;;;AACA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AAyBA;AACA;AACA;AACA,SAASG,4BAA4BA,CAACC,EAAU,EAAE;EAChD,IAAI,IAAAC,gCAAwB,EAAC,CAAC,EAAE;IAC9B,OAAOC,IAAI,CAACC,mBAAmB,CAACH,EAAE,CAAC;EACrC,CAAC,MAAM;IACL,OAAOI,OAAO,CAACC,OAAO,CAAC,CAAC;EAC1B;AACF;AAEA,MAAMC,cAA+C,GAAG;EACtDC,KAAK,EAAE,CAAC;EACRC,aAAa,EAAET;AACjB,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,SAASU,KAAKA,CAACC,OAA+B,EAAE;EACrD,MAAMC,MAAM,GAAGC,YAAY,CAACF,OAAO,CAAC;EACpC,MAAMG,QAAQ,GAAGC,cAAc,CAACH,MAAM,CAAC;EACvC,OAAOE,QAAQ;AACjB;AAOA,SAASD,YAAYA,CAACF,OAA+B,EAAmB;EACtE,OAAO;IACL,GAAGJ,cAAc;IACjB,GAAGI;EACL,CAAC;AACH;AAYA,SAASI,cAAcA,CAACH,MAAuB,EAAqB;EAClE,MAAME,QAAQ,GAAG;IACfF;EACF,CAAsB;;EAEtB;EACA,MAAMI,GAAG,GAAG;IACVC,KAAK,EAAEA,YAAK,CAACC,IAAI,CAACJ,QAAQ,CAAC;IAC3BK,SAAS,EAAEA,gBAAS,CAACD,IAAI,CAACJ,QAAQ,CAAC;IACnCM,IAAI,EAAEA,UAAI,CAACF,IAAI,CAACJ,QAAQ;EAC1B,CAAC;EAEDO,MAAM,CAACC,MAAM,CAACR,QAAQ,EAAEE,GAAG,CAAC;EAC5B,OAAOF,QAAQ;AACjB"}
1
+ {"version":3,"file":"setup.js","names":["_timers","require","_press","_type","_clear","universalJestAdvanceTimersBy","ms","jestFakeTimersAreEnabled","jest","advanceTimersByTime","Promise","resolve","defaultOptions","delay","advanceTimers","setup","options","config","createConfig","instance","createInstance","api","press","bind","longPress","type","clear","Object","assign"],"sources":["../../../src/user-event/setup/setup.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport { jestFakeTimersAreEnabled } from '../../helpers/timers';\nimport { PressOptions, press, longPress } from '../press';\nimport { TypeOptions, type } from '../type';\nimport { clear } from '../clear';\n\nexport interface UserEventSetupOptions {\n /**\n * Between some subsequent inputs like typing a series of characters\n * the code execution is delayed per `setTimeout` for (at least) `delay` seconds.\n * This moves the next changes at least to next macro task\n * and allows other (asynchronous) code to run between events.\n *\n * `null` prevents `setTimeout` from being called.\n *\n * @default 0\n */\n delay?: number;\n\n /**\n * Function to be called to advance fake timers. Setting it is necessary for\n * fake timers to work.\n *\n * @example jest.advanceTimersByTime\n */\n advanceTimers?: (delay: number) => Promise<void> | void;\n}\n\n/**\n * This functions allow wait to work correctly under both real and fake Jest timers.\n */\nfunction universalJestAdvanceTimersBy(ms: number) {\n if (jestFakeTimersAreEnabled()) {\n return jest.advanceTimersByTime(ms);\n } else {\n return Promise.resolve();\n }\n}\n\nconst defaultOptions: Required<UserEventSetupOptions> = {\n delay: 0,\n advanceTimers: universalJestAdvanceTimersBy,\n};\n\n/**\n * Creates a new instance of user event instance with the given options.\n *\n * @param options\n * @returns UserEvent instance\n */\nexport function setup(options?: UserEventSetupOptions) {\n const config = createConfig(options);\n const instance = createInstance(config);\n return instance;\n}\n\n/**\n * Options affecting all user event interactions.\n *\n * @param delay between some subsequent inputs like typing a series of characters\n * @param advanceTimers function to be called to advance fake timers\n */\nexport interface UserEventConfig {\n delay: number;\n advanceTimers: (delay: number) => Promise<void> | void;\n}\n\nfunction createConfig(options?: UserEventSetupOptions): UserEventConfig {\n return {\n ...defaultOptions,\n ...options,\n };\n}\n\n/**\n * UserEvent instance used to invoke user interaction functions.\n */\nexport interface UserEventInstance {\n config: UserEventConfig;\n\n press: (element: ReactTestInstance) => Promise<void>;\n longPress: (\n element: ReactTestInstance,\n options?: PressOptions\n ) => Promise<void>;\n\n /**\n * Simulate user pressing on a given `TextInput` element and typing given text.\n *\n * This method will trigger the events for each character of the text:\n * `keyPress`, `change`, `changeText`, `endEditing`, etc.\n *\n * It will also trigger events connected with entering and leaving the text\n * input.\n *\n * The exact events sent depend on the props of the TextInput (`editable`,\n * `multiline`, value, defaultValue, etc) and passed options.\n *\n * @param element TextInput element to type on\n * @param text Text to type\n * @param options Options affecting typing behavior:\n * - `skipPress` - if true, `pressIn` and `pressOut` events will not be\n * triggered.\n * - `submitEditing` - if true, `submitEditing` event will be triggered after\n * typing the text.\n */\n type: (\n element: ReactTestInstance,\n text: string,\n options?: TypeOptions\n ) => Promise<void>;\n\n /**\n * Simulate user clearing the text of a given `TextInput` element.\n *\n * This method will simulate:\n * 1. entering TextInput\n * 2. selecting all text\n * 3. pressing backspace to delete all text\n * 4. leaving TextInput\n *\n * @param element TextInput element to clear\n */\n clear: (element: ReactTestInstance) => Promise<void>;\n}\n\nfunction createInstance(config: UserEventConfig): UserEventInstance {\n const instance = {\n config,\n } as UserEventInstance;\n\n // We need to bind these functions, as they access the config through 'this.config'.\n const api = {\n press: press.bind(instance),\n longPress: longPress.bind(instance),\n type: type.bind(instance),\n clear: clear.bind(instance),\n };\n\n Object.assign(instance, api);\n return instance;\n}\n"],"mappings":";;;;;;AACA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,MAAA,GAAAH,OAAA;AAwBA;AACA;AACA;AACA,SAASI,4BAA4BA,CAACC,EAAU,EAAE;EAChD,IAAI,IAAAC,gCAAwB,EAAC,CAAC,EAAE;IAC9B,OAAOC,IAAI,CAACC,mBAAmB,CAACH,EAAE,CAAC;EACrC,CAAC,MAAM;IACL,OAAOI,OAAO,CAACC,OAAO,CAAC,CAAC;EAC1B;AACF;AAEA,MAAMC,cAA+C,GAAG;EACtDC,KAAK,EAAE,CAAC;EACRC,aAAa,EAAET;AACjB,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,SAASU,KAAKA,CAACC,OAA+B,EAAE;EACrD,MAAMC,MAAM,GAAGC,YAAY,CAACF,OAAO,CAAC;EACpC,MAAMG,QAAQ,GAAGC,cAAc,CAACH,MAAM,CAAC;EACvC,OAAOE,QAAQ;AACjB;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAMA,SAASD,YAAYA,CAACF,OAA+B,EAAmB;EACtE,OAAO;IACL,GAAGJ,cAAc;IACjB,GAAGI;EACL,CAAC;AACH;;AAEA;AACA;AACA;;AAkDA,SAASI,cAAcA,CAACH,MAAuB,EAAqB;EAClE,MAAME,QAAQ,GAAG;IACfF;EACF,CAAsB;;EAEtB;EACA,MAAMI,GAAG,GAAG;IACVC,KAAK,EAAEA,YAAK,CAACC,IAAI,CAACJ,QAAQ,CAAC;IAC3BK,SAAS,EAAEA,gBAAS,CAACD,IAAI,CAACJ,QAAQ,CAAC;IACnCM,IAAI,EAAEA,UAAI,CAACF,IAAI,CAACJ,QAAQ,CAAC;IACzBO,KAAK,EAAEA,YAAK,CAACH,IAAI,CAACJ,QAAQ;EAC5B,CAAC;EAEDQ,MAAM,CAACC,MAAM,CAACT,QAAQ,EAAEE,GAAG,CAAC;EAC5B,OAAOF,QAAQ;AACjB"}
@@ -1 +1 @@
1
- export { type } from './type';
1
+ export { type, TypeOptions } from './type';
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "TypeOptions", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _type.TypeOptions;
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "type", {
7
13
  enumerable: true,
8
14
  get: function () {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_type","require"],"sources":["../../../src/user-event/type/index.ts"],"sourcesContent":["export { type } from './type';\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA"}
1
+ {"version":3,"file":"index.js","names":["_type","require"],"sources":["../../../src/user-event/type/index.ts"],"sourcesContent":["export { type, TypeOptions } from './type';\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA"}
@@ -0,0 +1 @@
1
+ export declare function parseKeys(text: string): string[];
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.parseKeys = parseKeys;
7
+ const knownKeys = new Set(['Enter', 'Backspace']);
8
+ function parseKeys(text) {
9
+ const result = [];
10
+ let remainingText = text;
11
+ while (remainingText) {
12
+ const [token, rest] = getNextToken(remainingText);
13
+ if (token.length > 1 && !knownKeys.has(token)) {
14
+ throw new Error(`Unknown key "${token}" in "${text}"`);
15
+ }
16
+ result.push(token);
17
+ remainingText = rest;
18
+ }
19
+ return result;
20
+ }
21
+ function getNextToken(text) {
22
+ // Detect `{{` => escaped `{`
23
+ if (text[0] === '{' && text[1] === '{') {
24
+ return ['{', text.slice(2)];
25
+ }
26
+
27
+ // Detect `{key}` => special key
28
+ if (text[0] === '{') {
29
+ const endIndex = text.indexOf('}');
30
+ if (endIndex === -1) {
31
+ throw new Error(`Invalid key sequence "${text}"`);
32
+ }
33
+ return [text.slice(1, endIndex), text.slice(endIndex + 1)];
34
+ }
35
+ if (text[0] === '\n') {
36
+ return ['Enter', text.slice(1)];
37
+ }
38
+ return [text[0], text.slice(1)];
39
+ }
40
+ //# sourceMappingURL=parseKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseKeys.js","names":["knownKeys","Set","parseKeys","text","result","remainingText","token","rest","getNextToken","length","has","Error","push","slice","endIndex","indexOf"],"sources":["../../../src/user-event/type/parseKeys.ts"],"sourcesContent":["const knownKeys = new Set(['Enter', 'Backspace']);\n\nexport function parseKeys(text: string) {\n const result = [];\n\n let remainingText = text;\n while (remainingText) {\n const [token, rest] = getNextToken(remainingText);\n if (token.length > 1 && !knownKeys.has(token)) {\n throw new Error(`Unknown key \"${token}\" in \"${text}\"`);\n }\n\n result.push(token);\n remainingText = rest;\n }\n\n return result;\n}\n\nfunction getNextToken(text: string): [string, string] {\n // Detect `{{` => escaped `{`\n if (text[0] === '{' && text[1] === '{') {\n return ['{', text.slice(2)];\n }\n\n // Detect `{key}` => special key\n if (text[0] === '{') {\n const endIndex = text.indexOf('}');\n if (endIndex === -1) {\n throw new Error(`Invalid key sequence \"${text}\"`);\n }\n\n return [text.slice(1, endIndex), text.slice(endIndex + 1)];\n }\n\n if (text[0] === '\\n') {\n return ['Enter', text.slice(1)];\n }\n\n return [text[0], text.slice(1)];\n}\n"],"mappings":";;;;;;AAAA,MAAMA,SAAS,GAAG,IAAIC,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AAE1C,SAASC,SAASA,CAACC,IAAY,EAAE;EACtC,MAAMC,MAAM,GAAG,EAAE;EAEjB,IAAIC,aAAa,GAAGF,IAAI;EACxB,OAAOE,aAAa,EAAE;IACpB,MAAM,CAACC,KAAK,EAAEC,IAAI,CAAC,GAAGC,YAAY,CAACH,aAAa,CAAC;IACjD,IAAIC,KAAK,CAACG,MAAM,GAAG,CAAC,IAAI,CAACT,SAAS,CAACU,GAAG,CAACJ,KAAK,CAAC,EAAE;MAC7C,MAAM,IAAIK,KAAK,CAAE,gBAAeL,KAAM,SAAQH,IAAK,GAAE,CAAC;IACxD;IAEAC,MAAM,CAACQ,IAAI,CAACN,KAAK,CAAC;IAClBD,aAAa,GAAGE,IAAI;EACtB;EAEA,OAAOH,MAAM;AACf;AAEA,SAASI,YAAYA,CAACL,IAAY,EAAoB;EACpD;EACA,IAAIA,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAIA,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;IACtC,OAAO,CAAC,GAAG,EAAEA,IAAI,CAACU,KAAK,CAAC,CAAC,CAAC,CAAC;EAC7B;;EAEA;EACA,IAAIV,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;IACnB,MAAMW,QAAQ,GAAGX,IAAI,CAACY,OAAO,CAAC,GAAG,CAAC;IAClC,IAAID,QAAQ,KAAK,CAAC,CAAC,EAAE;MACnB,MAAM,IAAIH,KAAK,CAAE,yBAAwBR,IAAK,GAAE,CAAC;IACnD;IAEA,OAAO,CAACA,IAAI,CAACU,KAAK,CAAC,CAAC,EAAEC,QAAQ,CAAC,EAAEX,IAAI,CAACU,KAAK,CAACC,QAAQ,GAAG,CAAC,CAAC,CAAC;EAC5D;EAEA,IAAIX,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE;IACpB,OAAO,CAAC,OAAO,EAAEA,IAAI,CAACU,KAAK,CAAC,CAAC,CAAC,CAAC;EACjC;EAEA,OAAO,CAACV,IAAI,CAAC,CAAC,CAAC,EAAEA,IAAI,CAACU,KAAK,CAAC,CAAC,CAAC,CAAC;AACjC"}
@@ -1,3 +1,8 @@
1
1
  import { ReactTestInstance } from 'react-test-renderer';
2
- import { UserEventInstance } from '../setup';
3
- export declare function type(this: UserEventInstance, element: ReactTestInstance, text: string): Promise<void>;
2
+ import { UserEventConfig, UserEventInstance } from '../setup';
3
+ export interface TypeOptions {
4
+ skipPress?: boolean;
5
+ submitEditing?: boolean;
6
+ }
7
+ export declare function type(this: UserEventInstance, element: ReactTestInstance, text: string, options?: TypeOptions): Promise<void>;
8
+ export declare function emitTypingEvents(config: UserEventConfig, element: ReactTestInstance, key: string, currentText: string, previousText: string): Promise<void>;
@@ -3,16 +3,78 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.emitTypingEvents = emitTypingEvents;
6
7
  exports.type = type;
7
- var _utils = require("../utils");
8
+ var _hostComponentNames = require("../../helpers/host-component-names");
8
9
  var _eventBuilder = require("../event-builder");
9
- async function type(element, text) {
10
- // TODO provide real implementation
11
- await (0, _utils.wait)(this.config);
12
- (0, _utils.dispatchHostEvent)(element, 'focus', _eventBuilder.EventBuilder.Common.focus());
13
- await (0, _utils.wait)(this.config);
14
- (0, _utils.dispatchHostEvent)(element, 'changeText', text);
10
+ var _errors = require("../../helpers/errors");
11
+ var _pointerEvents = require("../../helpers/pointer-events");
12
+ var _utils = require("../utils");
13
+ var _parseKeys = require("./parseKeys");
14
+ async function type(element, text, options) {
15
+ if (!(0, _hostComponentNames.isHostTextInput)(element)) {
16
+ throw new _errors.ErrorWithStack(`type() works only with host "TextInput" elements. Passed element has type "${element.type}".`, type);
17
+ }
18
+
19
+ // Skip events if the element is disabled
20
+ if (element.props.editable === false || !(0, _pointerEvents.isPointerEventEnabled)(element)) {
21
+ return;
22
+ }
23
+ const keys = (0, _parseKeys.parseKeys)(text);
24
+ if (!options?.skipPress) {
25
+ (0, _utils.dispatchEvent)(element, 'pressIn', _eventBuilder.EventBuilder.Common.touch());
26
+ }
27
+ (0, _utils.dispatchEvent)(element, 'focus', _eventBuilder.EventBuilder.Common.focus());
28
+ if (!options?.skipPress) {
29
+ await (0, _utils.wait)(this.config);
30
+ (0, _utils.dispatchEvent)(element, 'pressOut', _eventBuilder.EventBuilder.Common.touch());
31
+ }
32
+ let currentText = element.props.value ?? element.props.defaultValue ?? '';
33
+ for (const key of keys) {
34
+ const previousText = element.props.value ?? currentText;
35
+ currentText = applyKey(previousText, key);
36
+ await emitTypingEvents(this.config, element, key, currentText, previousText);
37
+ }
38
+ const finalText = element.props.value ?? currentText;
15
39
  await (0, _utils.wait)(this.config);
16
- (0, _utils.dispatchHostEvent)(element, 'blur', _eventBuilder.EventBuilder.Common.blur());
40
+ if (options?.submitEditing) {
41
+ (0, _utils.dispatchEvent)(element, 'submitEditing', _eventBuilder.EventBuilder.TextInput.submitEditing(finalText));
42
+ }
43
+ (0, _utils.dispatchEvent)(element, 'endEditing', _eventBuilder.EventBuilder.TextInput.endEditing(finalText));
44
+ (0, _utils.dispatchEvent)(element, 'blur', _eventBuilder.EventBuilder.Common.blur());
45
+ }
46
+ async function emitTypingEvents(config, element, key, currentText, previousText) {
47
+ const isMultiline = element.props.multiline === true;
48
+ await (0, _utils.wait)(config);
49
+ (0, _utils.dispatchEvent)(element, 'keyPress', _eventBuilder.EventBuilder.TextInput.keyPress(key));
50
+
51
+ // According to the docs only multiline TextInput emits textInput event
52
+ // @see: https://github.com/facebook/react-native/blob/42a2898617da1d7a98ef574a5b9e500681c8f738/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts#L754
53
+ if (isMultiline) {
54
+ (0, _utils.dispatchEvent)(element, 'textInput', _eventBuilder.EventBuilder.TextInput.textInput(currentText, previousText));
55
+ }
56
+ (0, _utils.dispatchEvent)(element, 'change', _eventBuilder.EventBuilder.TextInput.change(currentText));
57
+ (0, _utils.dispatchEvent)(element, 'changeText', currentText);
58
+ const selectionRange = {
59
+ start: currentText.length,
60
+ end: currentText.length
61
+ };
62
+ (0, _utils.dispatchEvent)(element, 'selectionChange', _eventBuilder.EventBuilder.TextInput.selectionChange(selectionRange));
63
+
64
+ // According to the docs only multiline TextInput emits contentSizeChange event
65
+ // @see: https://reactnative.dev/docs/textinput#oncontentsizechange
66
+ if (isMultiline) {
67
+ const contentSize = (0, _utils.getTextContentSize)(currentText);
68
+ (0, _utils.dispatchEvent)(element, 'contentSizeChange', _eventBuilder.EventBuilder.TextInput.contentSizeChange(contentSize));
69
+ }
70
+ }
71
+ function applyKey(text, key) {
72
+ if (key === 'Enter') {
73
+ return `${text}\n`;
74
+ }
75
+ if (key === 'Backspace') {
76
+ return text.slice(0, -1);
77
+ }
78
+ return text + key;
17
79
  }
18
80
  //# sourceMappingURL=type.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"type.js","names":["_utils","require","_eventBuilder","type","element","text","wait","config","dispatchHostEvent","EventBuilder","Common","focus","blur"],"sources":["../../../src/user-event/type/type.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport { UserEventInstance } from '../setup';\nimport { dispatchHostEvent, wait } from '../utils';\nimport { EventBuilder } from '../event-builder';\n\nexport async function type(\n this: UserEventInstance,\n element: ReactTestInstance,\n text: string\n) {\n // TODO provide real implementation\n await wait(this.config);\n dispatchHostEvent(element, 'focus', EventBuilder.Common.focus());\n\n await wait(this.config);\n dispatchHostEvent(element, 'changeText', text);\n\n await wait(this.config);\n dispatchHostEvent(element, 'blur', EventBuilder.Common.blur());\n}\n"],"mappings":";;;;;;AAEA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,aAAA,GAAAD,OAAA;AAEO,eAAeE,IAAIA,CAExBC,OAA0B,EAC1BC,IAAY,EACZ;EACA;EACA,MAAM,IAAAC,WAAI,EAAC,IAAI,CAACC,MAAM,CAAC;EACvB,IAAAC,wBAAiB,EAACJ,OAAO,EAAE,OAAO,EAAEK,0BAAY,CAACC,MAAM,CAACC,KAAK,CAAC,CAAC,CAAC;EAEhE,MAAM,IAAAL,WAAI,EAAC,IAAI,CAACC,MAAM,CAAC;EACvB,IAAAC,wBAAiB,EAACJ,OAAO,EAAE,YAAY,EAAEC,IAAI,CAAC;EAE9C,MAAM,IAAAC,WAAI,EAAC,IAAI,CAACC,MAAM,CAAC;EACvB,IAAAC,wBAAiB,EAACJ,OAAO,EAAE,MAAM,EAAEK,0BAAY,CAACC,MAAM,CAACE,IAAI,CAAC,CAAC,CAAC;AAChE"}
1
+ {"version":3,"file":"type.js","names":["_hostComponentNames","require","_eventBuilder","_errors","_pointerEvents","_utils","_parseKeys","type","element","text","options","isHostTextInput","ErrorWithStack","props","editable","isPointerEventEnabled","keys","parseKeys","skipPress","dispatchEvent","EventBuilder","Common","touch","focus","wait","config","currentText","value","defaultValue","key","previousText","applyKey","emitTypingEvents","finalText","submitEditing","TextInput","endEditing","blur","isMultiline","multiline","keyPress","textInput","change","selectionRange","start","length","end","selectionChange","contentSize","getTextContentSize","contentSizeChange","slice"],"sources":["../../../src/user-event/type/type.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport { isHostTextInput } from '../../helpers/host-component-names';\nimport { EventBuilder } from '../event-builder';\nimport { ErrorWithStack } from '../../helpers/errors';\nimport { isPointerEventEnabled } from '../../helpers/pointer-events';\nimport { UserEventConfig, UserEventInstance } from '../setup';\nimport { dispatchEvent, wait, getTextContentSize } from '../utils';\n\nimport { parseKeys } from './parseKeys';\n\nexport interface TypeOptions {\n skipPress?: boolean;\n submitEditing?: boolean;\n}\n\nexport async function type(\n this: UserEventInstance,\n element: ReactTestInstance,\n text: string,\n options?: TypeOptions\n): Promise<void> {\n if (!isHostTextInput(element)) {\n throw new ErrorWithStack(\n `type() works only with host \"TextInput\" elements. Passed element has type \"${element.type}\".`,\n type\n );\n }\n\n // Skip events if the element is disabled\n if (element.props.editable === false || !isPointerEventEnabled(element)) {\n return;\n }\n\n const keys = parseKeys(text);\n\n if (!options?.skipPress) {\n dispatchEvent(element, 'pressIn', EventBuilder.Common.touch());\n }\n\n dispatchEvent(element, 'focus', EventBuilder.Common.focus());\n\n if (!options?.skipPress) {\n await wait(this.config);\n dispatchEvent(element, 'pressOut', EventBuilder.Common.touch());\n }\n\n let currentText = element.props.value ?? element.props.defaultValue ?? '';\n for (const key of keys) {\n const previousText = element.props.value ?? currentText;\n currentText = applyKey(previousText, key);\n\n await emitTypingEvents(\n this.config,\n element,\n key,\n currentText,\n previousText\n );\n }\n\n const finalText = element.props.value ?? currentText;\n await wait(this.config);\n\n if (options?.submitEditing) {\n dispatchEvent(\n element,\n 'submitEditing',\n EventBuilder.TextInput.submitEditing(finalText)\n );\n }\n\n dispatchEvent(\n element,\n 'endEditing',\n EventBuilder.TextInput.endEditing(finalText)\n );\n\n dispatchEvent(element, 'blur', EventBuilder.Common.blur());\n}\n\nexport async function emitTypingEvents(\n config: UserEventConfig,\n element: ReactTestInstance,\n key: string,\n currentText: string,\n previousText: string\n) {\n const isMultiline = element.props.multiline === true;\n\n await wait(config);\n dispatchEvent(element, 'keyPress', EventBuilder.TextInput.keyPress(key));\n\n // According to the docs only multiline TextInput emits textInput event\n // @see: https://github.com/facebook/react-native/blob/42a2898617da1d7a98ef574a5b9e500681c8f738/packages/react-native/Libraries/Components/TextInput/TextInput.d.ts#L754\n if (isMultiline) {\n dispatchEvent(\n element,\n 'textInput',\n EventBuilder.TextInput.textInput(currentText, previousText)\n );\n }\n\n dispatchEvent(element, 'change', EventBuilder.TextInput.change(currentText));\n dispatchEvent(element, 'changeText', currentText);\n\n const selectionRange = {\n start: currentText.length,\n end: currentText.length,\n };\n dispatchEvent(\n element,\n 'selectionChange',\n EventBuilder.TextInput.selectionChange(selectionRange)\n );\n\n // According to the docs only multiline TextInput emits contentSizeChange event\n // @see: https://reactnative.dev/docs/textinput#oncontentsizechange\n if (isMultiline) {\n const contentSize = getTextContentSize(currentText);\n dispatchEvent(\n element,\n 'contentSizeChange',\n EventBuilder.TextInput.contentSizeChange(contentSize)\n );\n }\n}\n\nfunction applyKey(text: string, key: string) {\n if (key === 'Enter') {\n return `${text}\\n`;\n }\n\n if (key === 'Backspace') {\n return text.slice(0, -1);\n }\n\n return text + key;\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface ContentSize {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ /**
6
+ * Simple function for getting mock the size of given text.
7
+ *
8
+ * It works by calculating height based on number of lines and width based on
9
+ * the longest line length. It does not take into account font size, font
10
+ * family, as well as different letter sizes.
11
+ *
12
+ * @param text text to be measure
13
+ * @returns width and height of the text
14
+ */
15
+ export declare function getTextContentSize(text: string): ContentSize;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getTextContentSize = getTextContentSize;
7
+ /**
8
+ * Simple function for getting mock the size of given text.
9
+ *
10
+ * It works by calculating height based on number of lines and width based on
11
+ * the longest line length. It does not take into account font size, font
12
+ * family, as well as different letter sizes.
13
+ *
14
+ * @param text text to be measure
15
+ * @returns width and height of the text
16
+ */
17
+
18
+ function getTextContentSize(text) {
19
+ const lines = text.split('\n');
20
+ const maxLineLength = Math.max(...lines.map(line => line.length));
21
+ return {
22
+ width: maxLineLength * 5,
23
+ height: lines.length * 16
24
+ };
25
+ }
26
+ //# sourceMappingURL=content-size.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-size.js","names":["getTextContentSize","text","lines","split","maxLineLength","Math","max","map","line","length","width","height"],"sources":["../../../src/user-event/utils/content-size.ts"],"sourcesContent":["export interface ContentSize {\n width: number;\n height: number;\n}\n\n/**\n * Simple function for getting mock the size of given text.\n *\n * It works by calculating height based on number of lines and width based on\n * the longest line length. It does not take into account font size, font\n * family, as well as different letter sizes.\n *\n * @param text text to be measure\n * @returns width and height of the text\n */\n\nexport function getTextContentSize(text: string): ContentSize {\n const lines = text.split('\\n');\n const maxLineLength = Math.max(...lines.map((line) => line.length));\n\n return {\n width: maxLineLength * 5,\n height: lines.length * 16,\n };\n}\n"],"mappings":";;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO,SAASA,kBAAkBA,CAACC,IAAY,EAAe;EAC5D,MAAMC,KAAK,GAAGD,IAAI,CAACE,KAAK,CAAC,IAAI,CAAC;EAC9B,MAAMC,aAAa,GAAGC,IAAI,CAACC,GAAG,CAAC,GAAGJ,KAAK,CAACK,GAAG,CAAEC,IAAI,IAAKA,IAAI,CAACC,MAAM,CAAC,CAAC;EAEnE,OAAO;IACLC,KAAK,EAAEN,aAAa,GAAG,CAAC;IACxBO,MAAM,EAAET,KAAK,CAACO,MAAM,GAAG;EACzB,CAAC;AACH"}
@@ -1,9 +1,9 @@
1
1
  import { ReactTestInstance } from 'react-test-renderer';
2
2
  /**
3
- * Dispatch event function used by User Event module.
3
+ * Basic dispatch event function used by User Event module.
4
4
  *
5
5
  * @param element element trigger event on
6
6
  * @param eventName name of the event
7
7
  * @param event event payload
8
8
  */
9
- export declare function dispatchHostEvent(element: ReactTestInstance, eventName: string, event: unknown): void;
9
+ export declare function dispatchEvent(element: ReactTestInstance, eventName: string, event: unknown): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.dispatchEvent = dispatchEvent;
7
+ var _act = _interopRequireDefault(require("../../act"));
8
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ /**
10
+ * Basic dispatch event function used by User Event module.
11
+ *
12
+ * @param element element trigger event on
13
+ * @param eventName name of the event
14
+ * @param event event payload
15
+ */
16
+ function dispatchEvent(element, eventName, event) {
17
+ const handler = getEventHandler(element, eventName);
18
+ if (!handler) {
19
+ return;
20
+ }
21
+ (0, _act.default)(() => {
22
+ handler(event);
23
+ });
24
+ }
25
+ function getEventHandler(element, eventName) {
26
+ const handleName = getEventHandlerName(eventName);
27
+ const handle = element.props[handleName];
28
+ if (typeof handle !== 'function') {
29
+ return undefined;
30
+ }
31
+ return handle;
32
+ }
33
+ function getEventHandlerName(eventName) {
34
+ return `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
35
+ }
36
+ //# sourceMappingURL=dispatch-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch-event.js","names":["_act","_interopRequireDefault","require","obj","__esModule","default","dispatchEvent","element","eventName","event","handler","getEventHandler","act","handleName","getEventHandlerName","handle","props","undefined","charAt","toUpperCase","slice"],"sources":["../../../src/user-event/utils/dispatch-event.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport act from '../../act';\n\n/**\n * Basic dispatch event function used by User Event module.\n *\n * @param element element trigger event on\n * @param eventName name of the event\n * @param event event payload\n */\nexport function dispatchEvent(\n element: ReactTestInstance,\n eventName: string,\n event: unknown\n) {\n const handler = getEventHandler(element, eventName);\n if (!handler) {\n return;\n }\n\n act(() => {\n handler(event);\n });\n}\n\nfunction getEventHandler(element: ReactTestInstance, eventName: string) {\n const handleName = getEventHandlerName(eventName);\n const handle = element.props[handleName] as unknown;\n if (typeof handle !== 'function') {\n return undefined;\n }\n\n return handle;\n}\n\nfunction getEventHandlerName(eventName: string) {\n return `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;\n}\n"],"mappings":";;;;;;AACA,IAAAA,IAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA4B,SAAAD,uBAAAE,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAE5B;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,aAAaA,CAC3BC,OAA0B,EAC1BC,SAAiB,EACjBC,KAAc,EACd;EACA,MAAMC,OAAO,GAAGC,eAAe,CAACJ,OAAO,EAAEC,SAAS,CAAC;EACnD,IAAI,CAACE,OAAO,EAAE;IACZ;EACF;EAEA,IAAAE,YAAG,EAAC,MAAM;IACRF,OAAO,CAACD,KAAK,CAAC;EAChB,CAAC,CAAC;AACJ;AAEA,SAASE,eAAeA,CAACJ,OAA0B,EAAEC,SAAiB,EAAE;EACtE,MAAMK,UAAU,GAAGC,mBAAmB,CAACN,SAAS,CAAC;EACjD,MAAMO,MAAM,GAAGR,OAAO,CAACS,KAAK,CAACH,UAAU,CAAY;EACnD,IAAI,OAAOE,MAAM,KAAK,UAAU,EAAE;IAChC,OAAOE,SAAS;EAClB;EAEA,OAAOF,MAAM;AACf;AAEA,SAASD,mBAAmBA,CAACN,SAAiB,EAAE;EAC9C,OAAQ,KAAIA,SAAS,CAACU,MAAM,CAAC,CAAC,CAAC,CAACC,WAAW,CAAC,CAAE,GAAEX,SAAS,CAACY,KAAK,CAAC,CAAC,CAAE,EAAC;AACtE"}
@@ -0,0 +1,2 @@
1
+ import { ReactTestInstance } from 'react-test-renderer';
2
+ export declare function isEditableTextInput(element: ReactTestInstance): boolean;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isEditableTextInput = isEditableTextInput;
7
+ var _hostComponentNames = require("../../helpers/host-component-names");
8
+ function isEditableTextInput(element) {
9
+ return (0, _hostComponentNames.isHostTextInput)(element) && element.props.editable !== false;
10
+ }
11
+ //# sourceMappingURL=host-components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-components.js","names":["_hostComponentNames","require","isEditableTextInput","element","isHostTextInput","props","editable"],"sources":["../../../src/user-event/utils/host-components.ts"],"sourcesContent":["import { ReactTestInstance } from 'react-test-renderer';\nimport { isHostTextInput } from '../../helpers/host-component-names';\n\nexport function isEditableTextInput(element: ReactTestInstance) {\n return isHostTextInput(element) && element.props.editable !== false;\n}\n"],"mappings":";;;;;;AACA,IAAAA,mBAAA,GAAAC,OAAA;AAEO,SAASC,mBAAmBA,CAACC,OAA0B,EAAE;EAC9D,OAAO,IAAAC,mCAAe,EAACD,OAAO,CAAC,IAAIA,OAAO,CAACE,KAAK,CAACC,QAAQ,KAAK,KAAK;AACrE"}
@@ -1,2 +1,6 @@
1
- export * from './events';
1
+ export * from './content-size';
2
+ export * from './dispatch-event';
3
+ export * from './host-components';
4
+ export * from './text-range';
2
5
  export * from './wait';
6
+ export * from './warn-about-real-timers';
@@ -3,14 +3,47 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- var _events = require("./events");
7
- Object.keys(_events).forEach(function (key) {
6
+ var _contentSize = require("./content-size");
7
+ Object.keys(_contentSize).forEach(function (key) {
8
8
  if (key === "default" || key === "__esModule") return;
9
- if (key in exports && exports[key] === _events[key]) return;
9
+ if (key in exports && exports[key] === _contentSize[key]) return;
10
10
  Object.defineProperty(exports, key, {
11
11
  enumerable: true,
12
12
  get: function () {
13
- return _events[key];
13
+ return _contentSize[key];
14
+ }
15
+ });
16
+ });
17
+ var _dispatchEvent = require("./dispatch-event");
18
+ Object.keys(_dispatchEvent).forEach(function (key) {
19
+ if (key === "default" || key === "__esModule") return;
20
+ if (key in exports && exports[key] === _dispatchEvent[key]) return;
21
+ Object.defineProperty(exports, key, {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _dispatchEvent[key];
25
+ }
26
+ });
27
+ });
28
+ var _hostComponents = require("./host-components");
29
+ Object.keys(_hostComponents).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _hostComponents[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _hostComponents[key];
36
+ }
37
+ });
38
+ });
39
+ var _textRange = require("./text-range");
40
+ Object.keys(_textRange).forEach(function (key) {
41
+ if (key === "default" || key === "__esModule") return;
42
+ if (key in exports && exports[key] === _textRange[key]) return;
43
+ Object.defineProperty(exports, key, {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _textRange[key];
14
47
  }
15
48
  });
16
49
  });
@@ -25,4 +58,15 @@ Object.keys(_wait).forEach(function (key) {
25
58
  }
26
59
  });
27
60
  });
61
+ var _warnAboutRealTimers = require("./warn-about-real-timers");
62
+ Object.keys(_warnAboutRealTimers).forEach(function (key) {
63
+ if (key === "default" || key === "__esModule") return;
64
+ if (key in exports && exports[key] === _warnAboutRealTimers[key]) return;
65
+ Object.defineProperty(exports, key, {
66
+ enumerable: true,
67
+ get: function () {
68
+ return _warnAboutRealTimers[key];
69
+ }
70
+ });
71
+ });
28
72
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_events","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_wait"],"sources":["../../../src/user-event/utils/index.ts"],"sourcesContent":["export * from './events';\nexport * from './wait';\n"],"mappings":";;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,OAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,OAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,OAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,KAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,KAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,KAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,KAAA,CAAAL,GAAA;IAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"index.js","names":["_contentSize","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_dispatchEvent","_hostComponents","_textRange","_wait","_warnAboutRealTimers"],"sources":["../../../src/user-event/utils/index.ts"],"sourcesContent":["export * from './content-size';\nexport * from './dispatch-event';\nexport * from './host-components';\nexport * from './text-range';\nexport * from './wait';\nexport * from './warn-about-real-timers';\n"],"mappings":";;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,YAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,YAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,YAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,cAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,cAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,cAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,cAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,eAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,eAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,eAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,eAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,UAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,UAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,UAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,UAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,KAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,KAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,KAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,KAAA,CAAAR,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,oBAAA,GAAAb,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAW,oBAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAS,oBAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAK,oBAAA,CAAAT,GAAA;IAAA;EAAA;AAAA"}
@@ -0,0 +1,4 @@
1
+ export interface TextRange {
2
+ start: number;
3
+ end: number;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=text-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-range.js","names":[],"sources":["../../../src/user-event/utils/text-range.ts"],"sourcesContent":["export interface TextRange {\n start: number;\n end: number;\n}\n"],"mappings":""}
@@ -0,0 +1 @@
1
+ export declare const warnAboutRealTimersIfNeeded: () => void;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.warnAboutRealTimersIfNeeded = void 0;
7
+ var _timers = require("../../helpers/timers");
8
+ const warnAboutRealTimersIfNeeded = () => {
9
+ const areFakeTimersEnabled = (0, _timers.jestFakeTimersAreEnabled)();
10
+ if (areFakeTimersEnabled) {
11
+ return;
12
+ }
13
+
14
+ // eslint-disable-next-line no-console
15
+ console.warn(`It is recommended to use userEvent with fake timers
16
+ Some events involve duration so your tests may take a long time to run.
17
+ For instance calling userEvent.longPress with real timers will take 500 ms.`);
18
+ };
19
+ exports.warnAboutRealTimersIfNeeded = warnAboutRealTimersIfNeeded;
20
+ //# sourceMappingURL=warn-about-real-timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warn-about-real-timers.js","names":["_timers","require","warnAboutRealTimersIfNeeded","areFakeTimersEnabled","jestFakeTimersAreEnabled","console","warn","exports"],"sources":["../../../src/user-event/utils/warn-about-real-timers.ts"],"sourcesContent":["import { jestFakeTimersAreEnabled } from '../../helpers/timers';\n\nexport const warnAboutRealTimersIfNeeded = () => {\n const areFakeTimersEnabled = jestFakeTimersAreEnabled();\n if (areFakeTimersEnabled) {\n return;\n }\n\n // eslint-disable-next-line no-console\n console.warn(`It is recommended to use userEvent with fake timers\nSome events involve duration so your tests may take a long time to run.\nFor instance calling userEvent.longPress with real timers will take 500 ms.`);\n};\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AAEO,MAAMC,2BAA2B,GAAGA,CAAA,KAAM;EAC/C,MAAMC,oBAAoB,GAAG,IAAAC,gCAAwB,EAAC,CAAC;EACvD,IAAID,oBAAoB,EAAE;IACxB;EACF;;EAEA;EACAE,OAAO,CAACC,IAAI,CAAE;AAChB;AACA,4EAA4E,CAAC;AAC7E,CAAC;AAACC,OAAA,CAAAL,2BAAA,GAAAA,2BAAA"}
@@ -0,0 +1,15 @@
1
+ > Why do I have a folder named ".expo" in my project?
2
+
3
+ The ".expo" folder is created when an Expo project is started using "expo start" command.
4
+
5
+ > What do the files contain?
6
+
7
+ - "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
8
+ - "packager-info.json": contains port numbers and process PIDs that are used to serve the application to the mobile device/simulator.
9
+ - "settings.json": contains the server configuration that is used to serve the application manifest.
10
+
11
+ > Should I commit the ".expo" folder?
12
+
13
+ No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
14
+
15
+ Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
@@ -0,0 +1,4 @@
1
+ {
2
+ "packagerPort": null,
3
+ "packagerPid": null
4
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "scheme": null,
3
+ "hostType": "lan",
4
+ "lanType": "ip",
5
+ "devClient": false,
6
+ "dev": true,
7
+ "minify": false,
8
+ "urlRandomness": null,
9
+ "https": false
10
+ }
@@ -1,7 +1,14 @@
1
1
  import * as React from 'react';
2
- import { render, screen, fireEvent } from '@testing-library/react-native';
2
+ import {
3
+ render,
4
+ screen,
5
+ fireEvent,
6
+ userEvent,
7
+ } from '@testing-library/react-native';
3
8
  import App from '../App';
4
9
 
10
+ jest.useFakeTimers();
11
+
5
12
  /**
6
13
  * A good place to start is having a tests that your component renders correctly.
7
14
  */
@@ -22,6 +29,9 @@ test('renders correctly', () => {
22
29
  * his point of view.
23
30
  */
24
31
  test('User can sign in successully with correct credentials', async () => {
32
+ // Setup User Event instance for realistic simulation of user interaction.
33
+ const user = userEvent.setup();
34
+
25
35
  // Idiom: no need to capture render output, as we will use `screen` for queries.
26
36
  render(<App />);
27
37
 
@@ -32,11 +42,11 @@ test('User can sign in successully with correct credentials', async () => {
32
42
  ).toBeOnTheScreen();
33
43
 
34
44
  // Hint: we can use `getByLabelText` to find our text inputs using their labels.
35
- fireEvent.changeText(screen.getByLabelText('Username'), 'admin');
36
- fireEvent.changeText(screen.getByLabelText('Password'), 'admin1');
45
+ await user.type(screen.getByLabelText('Username'), 'admin');
46
+ await user.type(screen.getByLabelText('Password'), 'admin1');
37
47
 
38
48
  // Hint: we can use `getByRole` to find our button with given text.
39
- fireEvent.press(screen.getByRole('button', { name: 'Sign In' }));
49
+ await user.press(screen.getByRole('button', { name: 'Sign In' }));
40
50
 
41
51
  // Idiom: since pressing button triggers async operation we need to use `findBy*` query to wait
42
52
  // for the action to complete.
@@ -67,15 +77,16 @@ test('User can sign in successully with correct credentials', async () => {
67
77
  * Note: that some times you will have to resort to `getByTestId`, but treat it as a last resort.
68
78
  */
69
79
  test('User will see errors for incorrect credentials', async () => {
80
+ const user = userEvent.setup();
70
81
  render(<App />);
71
82
 
72
83
  expect(
73
84
  screen.getByRole('header', { name: 'Sign in to Example App' })
74
85
  ).toBeOnTheScreen();
75
86
 
76
- fireEvent.changeText(screen.getByLabelText('Username'), 'admin');
77
- fireEvent.changeText(screen.getByLabelText('Password'), 'qwerty123');
78
- fireEvent.press(screen.getByRole('button', { name: 'Sign In' }));
87
+ await user.type(screen.getByLabelText('Username'), 'admin');
88
+ await user.type(screen.getByLabelText('Password'), 'qwerty123');
89
+ await user.press(screen.getByRole('button', { name: 'Sign In' }));
79
90
 
80
91
  // Hint: you can use custom Jest Native matcher to check text content.
81
92
  expect(await screen.findByRole('alert')).toHaveTextContent(
@@ -93,22 +104,29 @@ test('User will see errors for incorrect credentials', async () => {
93
104
  * Do not be afraid to write longer test scenarios, with repeating act and assert statements.
94
105
  */
95
106
  test('User can sign in after incorrect attempt', async () => {
107
+ const user = userEvent.setup();
96
108
  render(<App />);
97
109
 
98
110
  expect(
99
111
  screen.getByRole('header', { name: 'Sign in to Example App' })
100
112
  ).toBeOnTheScreen();
101
113
 
102
- fireEvent.changeText(screen.getByLabelText('Username'), 'admin');
103
- fireEvent.changeText(screen.getByLabelText('Password'), 'qwerty123');
104
- fireEvent.press(screen.getByRole('button', { name: 'Sign In' }));
114
+ const usernameInput = screen.getByLabelText('Username');
115
+ const passwordInput = screen.getByLabelText('Password');
116
+
117
+ await user.type(usernameInput, 'admin');
118
+ await user.type(passwordInput, 'qwerty123');
119
+ await user.press(screen.getByRole('button', { name: 'Sign In' }));
105
120
 
106
121
  expect(await screen.findByRole('alert')).toHaveTextContent(
107
122
  'Incorrect username or password'
108
123
  );
109
124
 
110
- fireEvent.changeText(screen.getByLabelText('Password'), 'admin1');
111
- fireEvent.press(screen.getByRole('button', { name: 'Sign In' }));
125
+ // Workaround for clearing TextInput, clear() function will be added soon.
126
+ fireEvent.changeText(passwordInput, '');
127
+
128
+ await user.type(passwordInput, 'admin1');
129
+ await user.press(screen.getByRole('button', { name: 'Sign In' }));
112
130
 
113
131
  expect(await screen.findByText('Welcome admin!')).toBeOnTheScreen();
114
132
  expect(