|  | 
| 1 | 1 | import { ReactTestInstance } from 'react-test-renderer'; | 
| 2 | 2 | import { jestFakeTimersAreEnabled } from '../../helpers/timers'; | 
| 3 |  | -import { PressOptions, press, longPress } from '../press'; | 
| 4 |  | -import { TypeOptions, type } from '../type'; | 
|  | 3 | +import { wrapAsync } from '../../helpers/wrap-async'; | 
| 5 | 4 | import { clear } from '../clear'; | 
|  | 5 | +import { PressOptions, press, longPress } from '../press'; | 
| 6 | 6 | import { ScrollToOptions, scrollTo } from '../scroll'; | 
|  | 7 | +import { TypeOptions, type } from '../type'; | 
|  | 8 | +import { wait } from '../utils'; | 
| 7 | 9 | 
 | 
| 8 | 10 | export interface UserEventSetupOptions { | 
| 9 | 11 |   /** | 
| @@ -141,15 +143,42 @@ function createInstance(config: UserEventConfig): UserEventInstance { | 
| 141 | 143 |     config, | 
| 142 | 144 |   } as UserEventInstance; | 
| 143 | 145 | 
 | 
| 144 |  | -  // We need to bind these functions, as they access the config through 'this.config'. | 
|  | 146 | +  // Bind interactions to given User Event instance. | 
| 145 | 147 |   const api = { | 
| 146 |  | -    press: press.bind(instance), | 
| 147 |  | -    longPress: longPress.bind(instance), | 
| 148 |  | -    type: type.bind(instance), | 
| 149 |  | -    clear: clear.bind(instance), | 
| 150 |  | -    scrollTo: scrollTo.bind(instance), | 
|  | 148 | +    press: wrapAndBindImpl(instance, press), | 
|  | 149 | +    longPress: wrapAndBindImpl(instance, longPress), | 
|  | 150 | +    type: wrapAndBindImpl(instance, type), | 
|  | 151 | +    clear: wrapAndBindImpl(instance, clear), | 
|  | 152 | +    scrollTo: wrapAndBindImpl(instance, scrollTo), | 
| 151 | 153 |   }; | 
| 152 | 154 | 
 | 
| 153 | 155 |   Object.assign(instance, api); | 
| 154 | 156 |   return instance; | 
| 155 | 157 | } | 
|  | 158 | + | 
|  | 159 | +/** | 
|  | 160 | + * Wraps user interaction with `wrapAsync` (temporarily disable `act` environment while | 
|  | 161 | + * calling & resolving the async callback, then flush the microtask queue) | 
|  | 162 | + * | 
|  | 163 | + * This implementation is sourced from `testing-library/user-event` | 
|  | 164 | + * @see https://github.com/testing-library/user-event/blob/7a305dee9ab833d6f338d567fc2e862b4838b76a/src/setup/setup.ts#L121 | 
|  | 165 | + */ | 
|  | 166 | +function wrapAndBindImpl< | 
|  | 167 | +  Args extends any[], | 
|  | 168 | +  Impl extends (this: UserEventInstance, ...args: Args) => Promise<unknown> | 
|  | 169 | +>(instance: UserEventInstance, impl: Impl) { | 
|  | 170 | +  function method(...args: Args) { | 
|  | 171 | +    return wrapAsync(() => | 
|  | 172 | +      // eslint-disable-next-line promise/prefer-await-to-then | 
|  | 173 | +      impl.apply(instance, args).then(async (result) => { | 
|  | 174 | +        await wait(instance.config); | 
|  | 175 | +        return result; | 
|  | 176 | +      }) | 
|  | 177 | +    ); | 
|  | 178 | +  } | 
|  | 179 | + | 
|  | 180 | +  // Copy implementation name to the returned function | 
|  | 181 | +  Object.defineProperty(method, 'name', { get: () => impl.name }); | 
|  | 182 | + | 
|  | 183 | +  return method as Impl; | 
|  | 184 | +} | 
0 commit comments