Reputation: 14033
I have some problems with testing TextInput
changes in react-native with jest and enzyme.
My component that handles user input basically looks like this (simplified):
class Search extends React.PureComponent {
onSearchTextChange = input => {
// do something awesome
};
render() {
return (
<View>
<TextInput
onChangeText={debounce(this.onSearchTextChange, 800)}
/>
</View>
);
}
}
I want to test the text input behaviour. This is what the test looks like right now:
it('should render a text input and react to user input', done => {
const mockOnSearchTextChange = jest.fn();
Search.prototype.onSearchTextChange = mockOnSearchTextChange;
const tree = shallow(<Search />);
const textInput = tree.find('TextInput');
expect(textInput).toHaveLength(1);
textInput.simulate('changeText', { target: { value: 'test' } });
expect(mockOnSearchTextChange).not.toHaveBeenCalled();
setTimeout(() => {
expect(mockOnSearchTextChange).toHaveBeenCalledWith('test');
done();
}, 1500);
});
When running this test, I get this error message
Expected mock function to have been called with: ["test"]
But it was not called.
So the mocked function is never called as expected. What am I missing?
Upvotes: 8
Views: 12036
Reputation: 191
There is no need to add another library. Jest and Enzyme can perform the required testing. Below is the definition of SearchBar component which receives a function as a prop. The function is called with the text typed.
const SearchBar = ({onSearch}) => {
return (
<View>
<TextInput
onChangeText={text => onSearch(text)}
/>
</View>
);
};
The testing can be carried as follows
const onSearch = jest.fn();
const wrapper = shallow(<SearchBar onSearch={onSearch} />);
wrapper.find('TextInput').simulate('changeText', 'test search text');
expect(onSearch).toHaveBeenCalledWith('test search text');
Upvotes: 6
Reputation: 4465
I was able to do this using react-native-testing-library
.
// ...
import { render, act, fireEvent } from 'react-native-testing-library'
// ...
it ('does stuff', () => {
const mock = jest.fn()
const component = render(<Search onSearchTextChange={mock}/>)
fireEvent.changeText(component.findByType(TextInput), 'test')
expect(mock).toHaveBeenCalledWith('test')
})
Upvotes: 5
Reputation: 63
You can add and testID in your TextInput Field and accessibilityLabel as one of the props, add both for ios and android compatibility, Here is the TextInput code.
<TextInput
placeholder='Email Address'
testID='#email'
accessibilityLabel='#email'
blurOnSubmit={ false }
onEndEditing={this.onSubmitLogin}
>
</TextInput>
In your test file do a shallow rendering, here
describe('Your component', () => {
it('Component: renders correctly', () => {
const tree = renderer.create(<YourComponent/>).toJSON();
expect(tree).toMatchSnapshot();
});
it('Has TextInput', () => {
const tree2 = renderer.create(<YourComponent/>).toJSON();
expect(findElement(tree2, '#email')).toBeDefined();
});
});
Then define the function findElement above describe. With console.warn you should see your props of TextInput and in that your testID
const findElement = function (tree2, element) {
let result = undefined
console.warn(tree2.children)
for(node in tree2.children){
if(tree2.children[node].props.testID = element) {
result = true
}
}
return result
}
It will test for all available TextInputs .... Note: Shallow rendering will only work if the TextInput is only one level deep(Inside one view only) if it is nested refer here - https://medium.com/@AidThompsin/heres-how-you-unit-test-textinput-with-react-native-63e1f7692b17
Upvotes: 0