Skip to content

Commit ea9fc0e

Browse files
committed
feat: basic paste() implementation
1 parent f0df299 commit ea9fc0e

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

src/user-event/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const userEvent = {
1616
type: (element: ReactTestInstance, text: string, options?: TypeOptions) =>
1717
setup().type(element, text, options),
1818
clear: (element: ReactTestInstance) => setup().clear(element),
19+
paste: (element: ReactTestInstance, text: string) => setup().paste(element, text),
1920
scrollTo: (element: ReactTestInstance, options: ScrollToOptions) =>
2021
setup().scrollTo(element, options),
2122
};

src/user-event/paste.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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 { isTextInputEditable } from '../helpers/text-input';
6+
import { EventBuilder } from './event-builder';
7+
import { UserEventInstance } from './setup';
8+
import { dispatchEvent, getTextContentSize, wait } from './utils';
9+
10+
export async function paste(
11+
this: UserEventInstance,
12+
element: ReactTestInstance,
13+
text: string,
14+
): Promise<void> {
15+
if (!isHostTextInput(element)) {
16+
throw new ErrorWithStack(
17+
`paste() only supports host "TextInput" elements. Passed element has type: "${element.type}".`,
18+
paste,
19+
);
20+
}
21+
22+
if (!isTextInputEditable(element) || !isPointerEventEnabled(element)) {
23+
return;
24+
}
25+
26+
// 1. Enter element
27+
dispatchEvent(element, 'focus', EventBuilder.Common.focus());
28+
29+
// 2. Select all
30+
const textToClear = element.props.value ?? element.props.defaultValue ?? '';
31+
const rangeToClear = { start: 0, end: textToClear.length };
32+
dispatchEvent(element, 'selectionChange', EventBuilder.TextInput.selectionChange(rangeToClear));
33+
34+
// 3. Paste the text
35+
dispatchEvent(element, 'change', EventBuilder.TextInput.change(text));
36+
dispatchEvent(element, 'changeText', text);
37+
38+
const rangeAfter = { start: text.length, end: text.length };
39+
dispatchEvent(element, 'selectionChange', EventBuilder.TextInput.selectionChange(rangeAfter));
40+
41+
// According to the docs only multiline TextInput emits contentSizeChange event
42+
// @see: https://reactnative.dev/docs/textinput#oncontentsizechange
43+
const isMultiline = element.props.multiline === true;
44+
if (isMultiline) {
45+
const contentSize = getTextContentSize(text);
46+
dispatchEvent(
47+
element,
48+
'contentSizeChange',
49+
EventBuilder.TextInput.contentSizeChange(contentSize),
50+
);
51+
}
52+
53+
// 4. Exit element
54+
await wait(this.config);
55+
dispatchEvent(element, 'endEditing', EventBuilder.TextInput.endEditing(text));
56+
dispatchEvent(element, 'blur', EventBuilder.Common.blur());
57+
}

src/user-event/setup/setup.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ReactTestInstance } from 'react-test-renderer';
22
import { jestFakeTimersAreEnabled } from '../../helpers/timers';
33
import { wrapAsync } from '../../helpers/wrap-async';
44
import { clear } from '../clear';
5+
import { paste } from '../paste';
56
import { PressOptions, press, longPress } from '../press';
67
import { ScrollToOptions, scrollTo } from '../scroll';
78
import { TypeOptions, type } from '../type';
@@ -139,6 +140,7 @@ function createInstance(config: UserEventConfig): UserEventInstance {
139140
longPress: wrapAndBindImpl(instance, longPress),
140141
type: wrapAndBindImpl(instance, type),
141142
clear: wrapAndBindImpl(instance, clear),
143+
paste: wrapAndBindImpl(instance, paste),
142144
scrollTo: wrapAndBindImpl(instance, scrollTo),
143145
};
144146

0 commit comments

Comments
 (0)