I am new to testing and I'm trying to test my app with react testing library. The first issue I ran into is testing functions that are inside of my components, like event handlers. I have found few examples where functions (event handlers) are passed in components as props but I don't want to do that if possible.
My Component:
import React, { useState } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { login } from 'actions/auth';
import Wrapper from './styled/Wrapper';
import Button from './styled/Button';
import Title from './styled/Title';
import { FormWrapper, StyledForm, FormField } from './styled/Form'
import Input from './styled/Input';
import Link from './styled/Link';
const Login = (props) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password } = formData;
const onChange = e => setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = e => {
e.preventDefault();
props.login(email, password);
}
if (props.isAuthenticated) {
return <Redirect to='/' />
}
return (
<Wrapper color='#F2F2F2'>
<FormWrapper>
<Title>Log In</Title>
<StyledForm data-testid='auth-form' onSubmit={e => onSubmit(e)}>
<FormField>
<Input
placeholder='Email'
type='email'
name='email'
value={email}
onChange={e => onChange(e)}
required
/>
</FormField>
<FormField>
<Input
placeholder='Password'
type='password'
name='password'
value={password}
onChange={e => onChange(e)}
required
/>
</FormField>
<Button type='submit' marginTop='6%'>LOG IN</Button>
</StyledForm>
<p>Don't have an account? <Link to='/register'>Sign Up!</Link> </p>
</FormWrapper>
</Wrapper>
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { login })(Login);
My Test file:
import React from 'react';
import { render, cleanup, fireEvent } from '@testing-library/react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import store from '../../store';
import Login from '../Login';
afterEach(cleanup);
const onChange = jest.fn();
test('<Login>', () => {
const { queryByTestId, getByPlaceholderText, getByText, debug } =
render(
<Provider store={store}>
<Router>
<Login />
</Router>
</Provider>);
expect(queryByTestId('auth-form')).toBeTruthy();
fireEvent.change(getByPlaceholderText('Email'), {
target: { value: '[email protected]' },
});
fireEvent.change(getByPlaceholderText('Password'), {
target: { value: 'testpassword' },
});
fireEvent.click(getByText('LOG IN'));
expect(onChange).toHaveBeenCalledTimes(1);
});
test output:
FAIL src/components/__tests__/Login.test.js
✕ <Login> (125 ms)
● <Login>
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
32 |
33 | fireEvent.click(getByText('LOG IN'));
> 34 | expect(onChange).toHaveBeenCalledTimes(1);
| ^
35 |
36 | });
at Object.<anonymous>.test (src/components/__tests__/Login.test.js:34:22)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 6.013 s
Ran all test suites related to changed files.
Watch Usage: Press w to show more.
Is there a way to make onSubmit function accessible to the test without passing it trough as a prop?