diff --git a/src/user-event/__tests__/__snapshots__/paste.test.tsx.snap b/src/user-event/__tests__/__snapshots__/paste.test.tsx.snap
new file mode 100644
index 000000000..fe5a510ca
--- /dev/null
+++ b/src/user-event/__tests__/__snapshots__/paste.test.tsx.snap
@@ -0,0 +1,530 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`paste() paste on empty text input 1`] = `
+[
+ {
+ "name": "focus",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 0,
+ "start": 0,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "change",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "eventCount": 0,
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "changeText",
+ "payload": "Hi!",
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 3,
+ "start": 3,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "endEditing",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "blur",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+]
+`;
+
+exports[`paste() paste on filled text input 1`] = `
+[
+ {
+ "name": "focus",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 6,
+ "start": 0,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "change",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "eventCount": 0,
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "changeText",
+ "payload": "Hi!",
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 3,
+ "start": 3,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "endEditing",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "blur",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+]
+`;
+
+exports[`paste() supports defaultValue prop: defaultValue: "Hello Default!" 1`] = `
+[
+ {
+ "name": "focus",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 14,
+ "start": 0,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "change",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "eventCount": 0,
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "changeText",
+ "payload": "Hi!",
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 3,
+ "start": 3,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "endEditing",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "blur",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+]
+`;
+
+exports[`paste() supports multiline: value: "Hello World!
+How are you?" multiline: true, 1`] = `
+[
+ {
+ "name": "focus",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 25,
+ "start": 0,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "change",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "eventCount": 0,
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "changeText",
+ "payload": "Hi!",
+ },
+ {
+ "name": "selectionChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "selection": {
+ "end": 3,
+ "start": 3,
+ },
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "contentSizeChange",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "contentSize": {
+ "height": 16,
+ "width": 15,
+ },
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "endEditing",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+ {
+ "name": "blur",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+]
+`;
+
+exports[`paste() works when not all events have handlers 1`] = `
+[
+ {
+ "name": "changeText",
+ "payload": "Hi!",
+ },
+ {
+ "name": "endEditing",
+ "payload": {
+ "currentTarget": {},
+ "isDefaultPrevented": [Function],
+ "isPersistent": [Function],
+ "isPropagationStopped": [Function],
+ "nativeEvent": {
+ "target": 0,
+ "text": "Hi!",
+ },
+ "persist": [Function],
+ "preventDefault": [Function],
+ "stopPropagation": [Function],
+ "target": {},
+ "timeStamp": 0,
+ },
+ },
+]
+`;
diff --git a/src/user-event/__tests__/paste.test.tsx b/src/user-event/__tests__/paste.test.tsx
new file mode 100644
index 000000000..1c01c8b0b
--- /dev/null
+++ b/src/user-event/__tests__/paste.test.tsx
@@ -0,0 +1,224 @@
+import * as React from 'react';
+import { TextInput, TextInputProps, View } from 'react-native';
+import { createEventLogger, getEventsNames } from '../../test-utils';
+import { render, userEvent, screen } from '../..';
+
+beforeEach(() => {
+ jest.useRealTimers();
+});
+
+function renderTextInputWithToolkit(props: TextInputProps = {}) {
+ const { events, logEvent } = createEventLogger();
+
+ render(
+ ,
+ );
+
+ const textInput = screen.getByTestId('input');
+
+ return {
+ events,
+ textInput,
+ };
+}
+
+describe('paste()', () => {
+ it('paste on empty text input', async () => {
+ jest.spyOn(Date, 'now').mockImplementation(() => 100100100100);
+ const { textInput, events } = renderTextInputWithToolkit();
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(getEventsNames(events)).toEqual([
+ 'focus',
+ 'selectionChange',
+ 'change',
+ 'changeText',
+ 'selectionChange',
+ 'endEditing',
+ 'blur',
+ ]);
+
+ expect(events).toMatchSnapshot();
+ });
+
+ it('paste on filled text input', async () => {
+ jest.spyOn(Date, 'now').mockImplementation(() => 100100100100);
+ const { textInput, events } = renderTextInputWithToolkit({
+ value: 'Hello!',
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(getEventsNames(events)).toEqual([
+ 'focus',
+ 'selectionChange',
+ 'change',
+ 'changeText',
+ 'selectionChange',
+ 'endEditing',
+ 'blur',
+ ]);
+
+ expect(events).toMatchSnapshot();
+ });
+
+ it.each(['modern', 'legacy'])('works with %s fake timers', async (type) => {
+ jest.useFakeTimers({ legacyFakeTimers: type === 'legacy' });
+ const { textInput, events } = renderTextInputWithToolkit({
+ value: 'Hello!',
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(getEventsNames(events)).toEqual([
+ 'focus',
+ 'selectionChange',
+ 'change',
+ 'changeText',
+ 'selectionChange',
+ 'endEditing',
+ 'blur',
+ ]);
+ });
+
+ it('supports defaultValue prop', async () => {
+ const { textInput, events } = renderTextInputWithToolkit({
+ defaultValue: 'Hello Default!',
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(getEventsNames(events)).toEqual([
+ 'focus',
+ 'selectionChange',
+ 'change',
+ 'changeText',
+ 'selectionChange',
+ 'endEditing',
+ 'blur',
+ ]);
+
+ expect(events).toMatchSnapshot('defaultValue: "Hello Default!"');
+ });
+
+ it('does respect editable prop', async () => {
+ const { textInput } = renderTextInputWithToolkit({
+ value: 'Hello!',
+ editable: false,
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(textInput.props.value).toBe('Hello!');
+ });
+
+ it('does respect pointer-events prop', async () => {
+ const { textInput } = renderTextInputWithToolkit({
+ value: 'Hello!',
+ pointerEvents: 'none',
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(textInput.props.value).toBe('Hello!');
+ });
+
+ it('supports multiline', async () => {
+ const { textInput, events } = renderTextInputWithToolkit({
+ value: 'Hello World!\nHow are you?',
+ multiline: true,
+ });
+
+ const user = userEvent.setup();
+ await user.paste(textInput, 'Hi!');
+
+ expect(getEventsNames(events)).toEqual([
+ 'focus',
+ 'selectionChange',
+ 'change',
+ 'changeText',
+ 'selectionChange',
+ 'contentSizeChange',
+ 'endEditing',
+ 'blur',
+ ]);
+
+ expect(events).toMatchSnapshot('value: "Hello World!\nHow are you?" multiline: true,');
+ });
+
+ it('works when not all events have handlers', async () => {
+ const { events, logEvent } = createEventLogger();
+ render(
+ ,
+ );
+
+ const user = userEvent.setup();
+ await user.paste(screen.getByTestId('input'), 'Hi!');
+
+ expect(getEventsNames(events)).toEqual(['changeText', 'endEditing']);
+
+ expect(events).toMatchSnapshot();
+ });
+
+ it('does NOT work on View', async () => {
+ render();
+
+ const user = userEvent.setup();
+ await expect(
+ user.paste(screen.getByTestId('input'), 'Hi!'),
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
+ `"paste() only supports host "TextInput" elements. Passed element has type: "View"."`,
+ );
+ });
+
+ // View that ignores props type checking
+ const AnyView = View as React.ComponentType;
+
+ it('does NOT bubble up', async () => {
+ const parentHandler = jest.fn();
+ render(
+
+
+ ,
+ );
+
+ const user = userEvent.setup();
+ await user.paste(screen.getByTestId('input'), 'Hi!');
+ expect(parentHandler).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/user-event/index.ts b/src/user-event/index.ts
index 6d8e50b63..17e0c946f 100644
--- a/src/user-event/index.ts
+++ b/src/user-event/index.ts
@@ -16,6 +16,7 @@ export const userEvent = {
type: (element: ReactTestInstance, text: string, options?: TypeOptions) =>
setup().type(element, text, options),
clear: (element: ReactTestInstance) => setup().clear(element),
+ paste: (element: ReactTestInstance, text: string) => setup().paste(element, text),
scrollTo: (element: ReactTestInstance, options: ScrollToOptions) =>
setup().scrollTo(element, options),
};
diff --git a/src/user-event/paste.ts b/src/user-event/paste.ts
new file mode 100644
index 000000000..80ed6b2bd
--- /dev/null
+++ b/src/user-event/paste.ts
@@ -0,0 +1,57 @@
+import { ReactTestInstance } from 'react-test-renderer';
+import { ErrorWithStack } from '../helpers/errors';
+import { isHostTextInput } from '../helpers/host-component-names';
+import { isPointerEventEnabled } from '../helpers/pointer-events';
+import { isTextInputEditable } from '../helpers/text-input';
+import { EventBuilder } from './event-builder';
+import { UserEventInstance } from './setup';
+import { dispatchEvent, getTextContentSize, wait } from './utils';
+
+export async function paste(
+ this: UserEventInstance,
+ element: ReactTestInstance,
+ text: string,
+): Promise {
+ if (!isHostTextInput(element)) {
+ throw new ErrorWithStack(
+ `paste() only supports host "TextInput" elements. Passed element has type: "${element.type}".`,
+ paste,
+ );
+ }
+
+ if (!isTextInputEditable(element) || !isPointerEventEnabled(element)) {
+ return;
+ }
+
+ // 1. Enter element
+ dispatchEvent(element, 'focus', EventBuilder.Common.focus());
+
+ // 2. Select all
+ const textToClear = element.props.value ?? element.props.defaultValue ?? '';
+ const rangeToClear = { start: 0, end: textToClear.length };
+ dispatchEvent(element, 'selectionChange', EventBuilder.TextInput.selectionChange(rangeToClear));
+
+ // 3. Paste the text
+ dispatchEvent(element, 'change', EventBuilder.TextInput.change(text));
+ dispatchEvent(element, 'changeText', text);
+
+ const rangeAfter = { start: text.length, end: text.length };
+ dispatchEvent(element, 'selectionChange', EventBuilder.TextInput.selectionChange(rangeAfter));
+
+ // According to the docs only multiline TextInput emits contentSizeChange event
+ // @see: https://reactnative.dev/docs/textinput#oncontentsizechange
+ const isMultiline = element.props.multiline === true;
+ if (isMultiline) {
+ const contentSize = getTextContentSize(text);
+ dispatchEvent(
+ element,
+ 'contentSizeChange',
+ EventBuilder.TextInput.contentSizeChange(contentSize),
+ );
+ }
+
+ // 4. Exit element
+ await wait(this.config);
+ dispatchEvent(element, 'endEditing', EventBuilder.TextInput.endEditing(text));
+ dispatchEvent(element, 'blur', EventBuilder.Common.blur());
+}
diff --git a/src/user-event/setup/setup.ts b/src/user-event/setup/setup.ts
index 5091793f1..53a4befa8 100644
--- a/src/user-event/setup/setup.ts
+++ b/src/user-event/setup/setup.ts
@@ -2,6 +2,7 @@ import { ReactTestInstance } from 'react-test-renderer';
import { jestFakeTimersAreEnabled } from '../../helpers/timers';
import { wrapAsync } from '../../helpers/wrap-async';
import { clear } from '../clear';
+import { paste } from '../paste';
import { PressOptions, press, longPress } from '../press';
import { ScrollToOptions, scrollTo } from '../scroll';
import { TypeOptions, type } from '../type';
@@ -119,6 +120,19 @@ export interface UserEventInstance {
*/
clear: (element: ReactTestInstance) => Promise;
+ /**
+ * Simulate user pasting the text to a given `TextInput` element.
+ *
+ * This method will simulate:
+ * 1. entering TextInput
+ * 2. selecting all text
+ * 3. paste the text
+ * 4. leaving TextInput
+ *
+ * @param element TextInput element to paste to
+ */
+ paste: (element: ReactTestInstance, text: string) => Promise;
+
/**
* Simlate user scorlling a ScrollView element.
*
@@ -139,6 +153,7 @@ function createInstance(config: UserEventConfig): UserEventInstance {
longPress: wrapAndBindImpl(instance, longPress),
type: wrapAndBindImpl(instance, type),
clear: wrapAndBindImpl(instance, clear),
+ paste: wrapAndBindImpl(instance, paste),
scrollTo: wrapAndBindImpl(instance, scrollTo),
};
diff --git a/website/docs/12.x/docs/api/events/user-event.mdx b/website/docs/12.x/docs/api/events/user-event.mdx
index 50d657ff9..fbf46af74 100644
--- a/website/docs/12.x/docs/api/events/user-event.mdx
+++ b/website/docs/12.x/docs/api/events/user-event.mdx
@@ -124,12 +124,10 @@ The `pressIn` and `pressOut` events are sent by default but can be skipped by pa
**Typing (for each character)**:
- `keyPress`
-- `textInput` (optional)
- `change`
- `changeText`
- `selectionChange`
-
-The `textInput` event is sent only for multiline text inputs.
+- `contentSizeChange` (only multiline)
**Leaving the element**:
@@ -144,7 +142,7 @@ The `submitEditing` event is skipped by default. It can sent by setting the `sub
```ts
clear(
element: ReactTestInstance,
-}
+)
```
Example
@@ -160,8 +158,6 @@ This function supports only host `TextInput` elements. Passing other element typ
### Sequence of events
-The sequence of events depends on the `multiline` prop and passed options.
-
Events will not be emitted if the `editable` prop is set to `false`.
**Entering the element**:
@@ -175,12 +171,52 @@ Events will not be emitted if the `editable` prop is set to `false`.
**Pressing backspace**:
- `keyPress`
-- `textInput` (optional)
- `change`
- `changeText`
- `selectionChange`
-The `textInput` event is sent only for multiline text inputs.
+**Leaving the element**:
+
+- `endEditing`
+- `blur`
+
+## `paste()`
+
+```ts
+paste(
+ element: ReactTestInstance,
+ text: string,
+)
+```
+
+Example
+
+```ts
+const user = userEvent.setup();
+await user.paste(textInput, 'Text to paste');
+```
+
+This helper simulates the user pasting given text to a `TextInput` element.
+
+This function supports only host `TextInput` elements. Passing other element types will result in throwing an error.
+
+### Sequence of events
+
+Events will not be emitted if the `editable` prop is set to `false`.
+
+**Entering the element**:
+
+- `focus`
+
+**Selecting all content**:
+
+- `selectionChange`
+
+**Pasting the text**:
+
+- `change`
+- `changeText`
+- `selectionChange`
**Leaving the element**: