Skip to content

Commit aa103b6

Browse files
pierrezimmermannbampierrezimmermannmdjastrzebski
authored
fix: prevent non editable textinputs from being updated through getByTestID (#1092)
* fix: prevent non editable textinputs from being updated through getByTestID * refactor: add comment to explain double check in isTextInput function * Update src/__tests__/fireEvent.test.tsx * Update src/__tests__/fireEvent.test.tsx Co-authored-by: pierrezimmermann <pierrez@nam.tech> Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
1 parent 5e918d5 commit aa103b6

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

src/__tests__/fireEvent.test.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,24 @@ test('should not fire on non-editable TextInput', () => {
235235
expect(onChangeTextMock).not.toHaveBeenCalled();
236236
});
237237

238+
test('should not fire on non-editable host TextInput', () => {
239+
const testID = 'my-text-input';
240+
const onChangeTextMock = jest.fn();
241+
const NEW_TEXT = 'New text';
242+
243+
const { getByTestId } = render(
244+
<TextInput
245+
editable={false}
246+
testID={testID}
247+
onChangeText={onChangeTextMock}
248+
placeholder="placeholder"
249+
/>
250+
);
251+
252+
fireEvent.changeText(getByTestId(testID), NEW_TEXT);
253+
expect(onChangeTextMock).not.toHaveBeenCalled();
254+
});
255+
238256
test('should not fire on non-editable TextInput with nested Text', () => {
239257
const placeholder = 'Test placeholder';
240258
const onChangeTextMock = jest.fn();

src/fireEvent.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ReactTestInstance } from 'react-test-renderer';
22
import act from './act';
3+
import { filterNodeByType } from './helpers/filterNodeByType';
34

45
type EventHandler = (...args: any) => unknown;
56

@@ -8,8 +9,21 @@ const isHostElement = (element?: ReactTestInstance) => {
89
};
910

1011
const isTextInput = (element?: ReactTestInstance) => {
12+
if (!element) {
13+
return false;
14+
}
15+
1116
const { TextInput } = require('react-native');
12-
return element?.type === TextInput;
17+
// We have to test if the element type is either the TextInput component
18+
// (which would if it is a composite component) or the string
19+
// TextInput (which would be true if it is a host component)
20+
// All queries but the one by testID return composite component and event
21+
// if all queries returned host components, since fireEvent bubbles up
22+
// it would trigger the parent prop without the composite component check
23+
return (
24+
filterNodeByType(element, TextInput) ||
25+
filterNodeByType(element, 'TextInput')
26+
);
1327
};
1428

1529
const isTouchResponder = (element?: ReactTestInstance) => {

src/helpers/filterNodeByType.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ import * as React from 'react';
33

44
export const filterNodeByType = (
55
node: ReactTestInstance | React.ReactElement,
6-
type: React.ElementType
6+
type: React.ElementType | string
77
) => node.type === type;

0 commit comments

Comments
 (0)