React testing a form - reactjs

I am trying to test my sign-in form for a react app. Basically the user signs up, and then the form will make an api post request to node.js server that will then post the data into a MySQL databases
The HTML for the form is:
<div className="signup">
<div className="signup__wrapper">
<div className="signup__banner">
<h2 className="signup__logo">Leep</h2>
<h2 className="signup__title">Please Sign Up to find artist</h2>
</div>
<form className="form" onSubmit={handleSubmit} autoComplete='off'>
<div className="form__container">
<input
className={!email.error? `form__input ${email.value? 'form__valid':''}`: "form__input error"}
type='text'
id='email'
data-testid='email'
name='email'
value={email.value}
onChange={handleEmail}
autoComplete='off'
/>
<label className="form__label" htmlFor="email">What's your email?</label>
</div>
<div className="form__container">
<input
className={!confirmEmail.error? `form__input ${confirmEmail.value? 'form__valid':''}`: "form__input error"}
type='text'
id='confirmemail'
data-testid='confirmemail'
name='confirmemail'
value={confirmEmail.value}
onChange={handleConfirmEmail}
/>
<label className="form__label" htmlFor="confirmemail">Please confirm your email?</label>
</div>
<div className="form__container">
<input
className={!username.error? `form__input ${username.value? 'form__valid':''}`: "form__input error"}
type='text'
id='username'
data-testid='username'
name='username'
value={username.value}
onChange={handleUserName}
/>
<label className="form__label" htmlFor="username">What's your user name?</label>
</div>
<div className="form__container">
<input
className={!password.error? `form__input ${password.value? 'form__valid':''}`: "form__input error"}
type='password'
id='password'
name='password'
data-testid='password'
value={password.value}
onChange={handlePassword}
/>
<label className="form__label" htmlFor="password">What's your password?</label>
</div>
<div className="form__container">
<input
className={!confirmPassword.error? `form__input ${confirmPassword.value? 'form__valid':''}`: "form__input error"}
type='password'
id='confirmPassword'
data-testid='confirmPassword'
name='confirmPassword'
value={confirmPassword.value}
onChange={handleConfirmPassword}
/>
<label className="form__label" htmlFor="confirmPassword">Please confirm your password</label>
</div>
<button className="form__btn" type="submit">
Sign up
</button>
<div className="signup__redirect">
<h3 className="signup__redirect--message">Already have an account?</h3>
<Router>
<Link className="signup__redirect--link" to='/login'>
Log in.
</Link>
</Router>
</div>
</form>
</div>
</div>
And here is the code that I am trying to use to test the form submission:
import React from "react";
import ReactDOM from "react-dom";
import SignupPage from "./SignupPage";
import {render, screen, waitFor } from '#testing-library/react'
import user from '#testing-library/user-event'
it("renders without crashing", ()=> {
const div = document.createElement("div")
ReactDOM.render(<SignupPage></SignupPage>, div)
})
describe('SignUpform', () => {
const onSubmit = jest.fn();
window.alert = jest.fn()
beforeEach(() => {
onSubmit.mockClear()
render(<SignupPage onSubmit={onSubmit} />)
});
it('onSubmit is called when all fields pass validation', async () => {
window.alert = () => {};
user.type(getEmail(), 'test#gmail.com')
user.type(confirmEmail(), 'test#gmail.com')
user.type(getUsername(), 'test')
user.type(getPassword(), '1234')
user.type(getConfirmPassword(), '1234')
user.click(screen.getByRole('button'))
await waitFor(() => {
expect(onSubmit).toBeCalledWith({
email: 'test#gmail.com',
confirmemail: 'test#gmail.com',
username: 'test',
password: '1234',
confirmpassword: '1234',
})
expect(onSubmit).toHaveBeenCalledTimes(1)
})
});
})
function getEmail () {
return screen.getByTestId('email', {
name: /email/i
})
}
function confirmEmail () {
return screen.getByTestId('confirmemail', {
name: /confirmemail/i
})
}
function getUsername () {
return screen.getByTestId('username', {
name: /username/i
})
}
function getPassword () {
return screen.getByTestId('password', {
name: /password/i
})
}
function getConfirmPassword() {
return screen.getByTestId('confirmPassword', {
name: /confirmpassword/i
})
}
console out put of the error that is followed by the html elements of the form
here is where the code is stating the error I am not sure what is wrong.

Related

React, functional component. Input focus is thrown off when a character is entered

I'm new in react. The problem is this - when I enter data into the input, my focus is reset. I understand that it happens due to changeHandler. But I don't understand how to change it. I've seen similar problems, but they are all related to class components. I would like to implement the solution exactly in a functional component, not using classes.
import React, { useContext, useEffect, useState } from 'react'
import { AuthContext } from '../context/AuthContext'
import axios from 'axios';
import { render } from '#testing-library/react';
export const AuthPage = () => {
const auth = useContext(AuthContext)
const [typeOfForm, setTypeOfForm] = useState('login')
const [form, setForm] = useState({
email: '', password: ''
})
const loginHandler = async () => {
try {
var config = {
headers: { 'Access-Control-Allow-Origin': '*' }
};
axios.post('http://localhost:5000/api/login', { ...form }, { headers: { 'Authorization': `Bearer ${auth.token}` } })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const registerHandler = async () => {
try {
var config = {
headers: { 'Authorization': `Bearer ${auth.token}` }
};
axios.post('http://localhost:5000/api/register', { ...form })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value })
}
return (
<div className="App" key="editor2">
<div className="logreg-bg"></div>
<a href="/">
<h1 id="logreg-logo">Animal Assistance <br /> <span id="logreg-logo-down">save nature togehter</span></h1>
</a>
{typeOfForm == 'login' ? <LoginForm /> : <RegisterForm />}
<h1 id="logreg-logo2"> Created by: <br /> <span id="logreg-logo-down2">PTN</span></h1>
</div>
);
function LoginForm() {
return (
<div id="logreg-form-container">
<h1 id="form-header">Log in</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Email"
type="text"
id="login"
name="email"
value={form.email}
onChange={changeHandler}
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Password"
type="password"
id="password"
name="password"
value={form.password}
onChange={changeHandler}
required />
<div id="logreg-button-container">
<button
onClick={registerHandler}
id="logreg-form-button"
>Login</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={() => setTypeOfForm('register')}>Register</a>
</div>
</div>
)
}
function RegisterForm() {
return (
<div id="logreg-form-container">
<h1 id="form-header">Register</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Введите email"
value={form.email}
onChange={changeHandler}
type="text"
id="login"
name="email"
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Введите пароль"
value={form.password}
onChange={changeHandler}
type="password"
id="password"
name="password"
required />
<div id="logreg-button-container">
<button
type="submit"
id="logreg-form-button"
>Register</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={() => setTypeOfForm('login')}>Login</a>
</div>
</div>
)
}
}
export default AuthPage;
Problems:
Focus is being lost because currently, input changes the state of a higher level component. The automatically causes a re-rendering of its child (the login or sign up form), because it is being completely defined again.
This causes an automatic re-render since React and browser think it
got a COMPLETELY NEW component.
Solutions:
Move the form state, and changeHandler function, to each respective form component, and allow them to manage their state independently. That way, this won't happen.
Recommended Approach:
If you want to form and changleHandler in a higher level component, then define the child components (Login and Sign Up) separately from AuthPage. Then just pass them the form state, and changeHandler function, as props.
Below if the 2nd approach being implemented
Since you would define both components separately, ensure you pass all the variables and functions in AuthPage, that are needed in each form, as props/parameters too. This is for functional purposes, and because it is best practice for maintenance on react apps.
Let me know if it helps :)
import React, { useContext, useEffect, useState } from 'react'
import { AuthContext } from '../context/AuthContext'
import axios from 'axios';
import { render } from '#testing-library/react';
function LoginForm({form, changeFormType, changeHandler, registerHandler}) {
return (
<div id="logreg-form-container">
<h1 id="form-header">Log in</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Email"
type="text"
id="login"
name="email"
value={form.email}
onChange={changeHandler}
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Password"
type="password"
id="password"
name="password"
value={form.password}
onChange={changeHandler}
required />
<div id="logreg-button-container">
<button
onClick={registerHandler}
id="logreg-form-button"
>Login</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={changeFormType}>Register</a>
</div>
</div>
)
}
function RegisterForm({form, changeFormType, changeHandler}) {
return (
<div id="logreg-form-container">
<h1 id="form-header">Register</h1>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="email" id="login-label">Email</label>
</div>
<input
placeholder="Введите email"
value={form.email}
onChange={changeHandler}
type="text"
id="login"
name="email"
required />
</div>
<div id="label-logreg-input">
<div className="logreg-labels">
<label htmlFor="password" id="password-label">Password</label>
</div>
<input
placeholder="Введите пароль"
value={form.password}
onChange={changeHandler}
type="password"
id="password"
name="password"
required />
<div id="logreg-button-container">
<button
type="submit"
id="logreg-form-button"
>Register</button>
</div>
</div>
<div id="go-to-else-container">
<a id="go-to-else"
onClick={changeFormType}>Login</a>
</div>
</div>
)
}
const AuthPage = () => {
const auth = useContext(AuthContext)
const [typeOfForm, setTypeOfForm] = useState('login')
const [form, setForm] = useState({
email: '', password: ''
})
const loginHandler = async () => {
try {
var config = {
headers: { 'Access-Control-Allow-Origin': '*' }
};
axios.post('http://localhost:5000/api/login', { ...form }, { headers: { 'Authorization': `Bearer ${auth.token}` } })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const registerHandler = async () => {
try {
var config = {
headers: { 'Authorization': `Bearer ${auth.token}` }
};
axios.post('http://localhost:5000/api/register', { ...form })
.then(response => response.data.map(part => { auth.login(part.token, part.userId); console.log(part) }))
.catch(function (error) {
console.log(error);
});
} catch (e) { }
}
const changeHandler = event => {
setForm({ ...form, [event.target.name]: event.target.value })
}
const changeFormType = event =>{
//add your condition based of e.target
setTypeOfForm('login')
//add your condition based of e.target
setTypeOfForm('register')
}
return (
<div className="App" key="editor2">
<div className="logreg-bg"></div>
<a href="/">
<h1 id="logreg-logo">Animal Assistance <br /> <span id="logreg-logo-down">save nature togehter</span></h1>
</a>
{typeOfForm == 'login' ? <LoginForm
changeHandler={changeHandler}
form={form}
changeFormType={changeFormType}
registerHandler={registerHandler}/>
: <RegisterForm
changeHandler={changeHandler}
form={form}
changeFormType={changeFormType}
/>}
<h1 id="logreg-logo2"> Created by: <br /> <span id="logreg-logo-down2">PTN</span></h1>
</div>
);
}
export default AuthPage;

Getting bad request error on forn submission in react

This the component I created. I can get the contact in console but throws error on submission. I can post the data through Postman; the problem occurs when I submit the form. Where is the error in the handlesubmit function?
import axios from 'axios';
import React, { useState } from 'react';
const ContactForm = () => {
const [contact, setContact] = useState({
firstName: '',
lastName: '',
phoneNumber: '',
email: '',
message: '',
});
function handleChange(e) {
setContact({ ...contact, [e.target.name]: [e.target.value] });
}
function hanhdleSubmit(e) {
e.preventDefault();
console.log(contact);
axios
.post('http://localhost:8080/contact', contact)
.then((response) => {
console.log('Response after post api', response.data);
})
.catch((error) => {
console.log('Error while post api', error);
});
}
return (
<div className="box poptrox-popup ">
<form onSubmit={hanhdleSubmit} noValidate>
<div className="row gtr-uniform">
<div className="col-6 col-12-xsmall">
<input
type="text"
placeholder="First Name"
value={contact.firstName}
name="firstName"
onChange={handleChange}
autoComplete="off"
/>
<br />
</div>
<div className="col-6 col-12-xsmall">
<input
type="text"
placeholder="Last Name"
value={contact.lastName}
name="lastName"
onChange={handleChange}
autoComplete="off"
/>
<br />
</div>
<div className="col-6 col-12-xsmall">
<input
type="tel"
placeholder="Phone Number"
value={contact.phoneNumber}
name="phoneNumber"
onChange={handleChange}
autoComplete="off"
/>
<br />
</div>
<div className="col-6 col-12-xsmall">
<input
type="email"
placeholder="Email"
value={contact.email}
name="email"
onChange={handleChange}
autoComplete="off"
/>
<br />
</div>
<div className="col-6 col-12-xsmall">
<textarea
placeholder="Please type what you are looking from us?"
value={contact.message}
name="message"
onChange={handleChange}
/>
<br />
</div>
<div className="col-12">
<button type="submit">Submit</button>
<h1>First Name:{contact.firstName}</h1>
<h1>Last Name:{contact.lastName}</h1>
<h1>Phone Number:{contact.phoneNumber}</h1>
<h1>Email:{contact.email}</h1>
<h1>message:{contact.message}</h1>
</div>
</div>
</form>
</div>
);
};
export default ContactForm;
This is the error I'm getting:
{
"timestamp": "2020-12-04T18:32:39.945+00:00",
"status": 400,
"error": "Bad Request",
"message": "",
"path": "/contact"
}
I think it's the syntax of the body sent to the backend, the second parameter of your axios.post should be an object :
axios
.post('http://localhost:8080/contact', contact)
should be
axios
.post('http://localhost:8080/contact', { contact })

I have a form component I am passing to App.js but I am getting this error

Getting this error when render the app.
SignIn(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
SignIn.js
import React, { useState, useRef } from "react";
import axios from "axios";
import swal from "sweetalert";
import "./SignUp.css";
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: "", password: "" });
const usernameFieldRef = useRef();
const passwordFieldRef = useRef();
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value });
};
const handleSubmit = event => {
event.preventDefault();
console.log('login');
const username = usernameFieldRef.current.value;
const password = passwordFieldRef.current.value;
axios
.post("https://foodiefun-api.herokuapp.com/api/auth/login", {
username,
password
})
.then(res => {
console.log("DATA", res.data)
localStorage.setItem('token', res.data.token)
swal(
"Welcome to Foodie Fun!",
"You are now signed in, enjoy your stay!",
"success"
);
})
.catch(err => {
console.log('LOGIN FAILED', err.response); // There was an error creating the data and logs to console
});
return (
<div class="page-content">
<div class="form-v6-content">
<div class="form-left">
<img className="form-image" style={{ linearGradient: "red, blue", opacity: ".6" }} src={image} alt="form" />
</div>
<form
onSubmit={handleSubmit}
class="form-detail"
method="post">
<h2>Register Form</h2>
<div class="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
class="input-text"
placeholder="Enter Desired User Name"
required />
</div>
<div class="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
class="input-text"
placeholder="Password"
required />
</div>
<div class="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
class="input-text"
placeholder="Comfirm Password"
required />
</div>
<div class="form-row-last">
<input type="submit"
name="register"
class="register"
value="Register" />
</div>
</form>
</div>
</div>
)
}
}
export default SignIn
App.js
import React, { useState } from "react";
import "./App.css";
import Form from "./Components/SignIn";
import ReviewForm from "./Components/ReviewForm/ReviewForm";
import UserInfo from "./Components/userInfo";
import mockarray from "./Components/mockarray";
import Navbar from "./Components/Navbar";
import RecipeApp from "./recipes/RecipeApp";
import SignUp from "./Components/SignUp";
import SignIn from "./Components/SignIn";
const App = () => {
const [reviews, setReviews] = useState([]);
const addReview = restaurant => {
setReviews([...reviews, { ...restaurant, id: Date.now() }]);
};
return (
<div className="App">
<Navbar />
<SignUp />
<SignIn />
{/* <RecipeApp /> */}
{/* <ReviewForm /> */}
{/* <ReviewForm addReview={addReview} /> */}
{console.log(reviews)}
{/* <UserInfo data = {mockarray} /> */}
</div>
);
};
export default App;
Two forms should be rendering on the screen but when I comment in the SignIn page I get this error. A couple of people have looked at it and they both say everything is right. I'm stumped!
Your return statement is inside the handleSubmit function.
You need to return your state outside handleSubmit function :
import React, { useState, useRef } from "react";
import axios from "axios";
import swal from "sweetalert";
import "./SignUp.css";
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: "", password: "" });
const usernameFieldRef = useRef();
const passwordFieldRef = useRef();
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value });
};
const handleSubmit = event => {
event.preventDefault();
console.log('login');
const username = usernameFieldRef.current.value;
const password = passwordFieldRef.current.value;
axios
.post("https://foodiefun-api.herokuapp.com/api/auth/login", {
username,
password
})
.then(res => {
console.log("DATA", res.data)
localStorage.setItem('token', res.data.token)
swal(
"Welcome to Foodie Fun!",
"You are now signed in, enjoy your stay!",
"success"
);
})
.catch(err => {
console.log('LOGIN FAILED', err.response); // There was an error creating the data and logs to console
});
}
return (
<div class="page-content">
<div class="form-v6-content">
<div class="form-left">
<img className="form-image" style={{ linearGradient: "red, blue", opacity: ".6" }} src={image} alt="form" />
</div>
<form
onSubmit={handleSubmit}
class="form-detail"
method="post">
<h2>Register Form</h2>
<div class="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
class="input-text"
placeholder="Enter Desired User Name"
required />
</div>
<div class="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
class="input-text"
placeholder="Password"
required />
</div>
<div class="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
class="input-text"
placeholder="Comfirm Password"
required />
</div>
<div class="form-row-last">
<input type="submit"
name="register"
class="register"
value="Register" />
</div>
</form>
</div>
</div>
)
}
export default SignIn
Working code : https://codesandbox.io/s/divine-field-kkfd6
Not sure if it's a typo on the code of your question or in your acctual code but the return is inside handleSubmit.
import React, { useState, useRef } from 'react'
import axios from 'axios'
import swal from 'sweetalert'
import './SignUp.css'
import image from './img/signup.jpg'
const SignIn = () => {
const [creds, setCreds] = useState({ userName: '', password: '' })
const usernameFieldRef = useRef()
const passwordFieldRef = useRef()
const changeHandler = e => {
setCreds({ ...creds, [e.target.name]: e.target.value })
}
const handleSubmit = event => {
event.preventDefault()
console.log('login')
const username = usernameFieldRef.current.value
const password = passwordFieldRef.current.value
axios
.post('https://foodiefun-api.herokuapp.com/api/auth/login', {
username,
password
})
.then(res => {
console.log('DATA', res.data)
localStorage.setItem('token', res.data.token)
swal(
'Welcome to Foodie Fun!',
'You are now signed in, enjoy your stay!',
'success'
)
})
.catch(err => {
console.log('LOGIN FAILED', err.response) // There was an error creating the data and logs to console
})
}
return (
<div className="page-content">
<div className="form-v6-content">
<div className="form-left">
<img
className="form-image"
style={{ linearGradient: 'red, blue', opacity: '.6' }}
src={image}
alt="form"
/>
</div>
<form onSubmit={handleSubmit} className="form-detail" method="post">
<h2>Register Form</h2>
<div className="form-row">
<input
ref={usernameFieldRef}
onChange={changeHandler}
// value={creds.userName}
type="text"
name="id"
id="user-name"
className="input-text"
placeholder="Enter Desired User Name"
required
/>
</div>
<div className="form-row">
<input
ref={passwordFieldRef}
onChange={changeHandler}
value={creds.password}
type="password"
name="password"
id="password"
className="input-text"
placeholder="Password"
required
/>
</div>
<div className="form-row">
<input
type="password"
name="comfirm-password"
id="comfirm-password"
className="input-text"
placeholder="Comfirm Password"
required
/>
</div>
<div className="form-row-last">
<input
type="submit"
name="register"
className="register"
value="Register"
/>
</div>
</form>
</div>
</div>
)
}
export default SignIn

Unable to type in input after adding value in React Js

I have tried with the following code with react js
import React, { Component } from 'react';
import Sidebar from './../Sidebar';
import Header from './../Header';
import {get_profile} from './../services/Services';
import $ from 'jquery';
export default class Profile extends Component {
constructor(props) {
super(props);
this.state = { userDetails: '' } ;
}
componentWillMount() {
$(window).scrollTop(0)
console.log('sdfds')
get_profile().then((response) => {
var userResults = $.parseJSON(response.text);
this.setState({ userDetails: userResults.response });
console.log(userResults);
}).catch((error) => {
//alert(error)
console.log(error);
});
}
handleChange(event) {
console.log(event.target.id)
this.setState({[event.target.name]: event.target.value});
}
render() {
return (
<div className="admin-panel">
<Sidebar />
<Header />
<div className="main-content">
<div className="contents">
<div className="container-fluid">
<div className="row">
<div className="col-sm-6">
<h2 className="page-title">Profile</h2>
<div className="form-group">
<label >First Name</label>
<input type="text" id="firstName" className="form-control" value={this.state.userDetails.firstName} />
</div>
<div className="form-group">
<label >Last Name</label>
<input type="text" id="lastName" className="form-control" value={this.state.userDetails.lastName} />
</div>
<div className="form-group">
<label >Email</label>
<input type="text" id="email" name="email" className="form-control" value={this.state.userDetails.email} />
</div>
<button type="button" className="btn btn-squared btn-success margin-inline" onClick={(e)=> {this.profileUpdate()}}>Update</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
After fetching the results i'm unable to edit the input box value. I have tried with defaultValue but that also not working for me. I'm struck with this issue, Kindly help me to solve the issue.
Just pass an onChange handler to the input which will update the value of the corresponding key of userDetails like this:
<input
...
value={this.state.userDetails.firstName}
onChange={this.onChange}
/>
onChange(e) {
this.setState((previousState) => {
const userDetails = previousState.userDetails
return { userDetails: {...userDetails, firstName: e.target.value} }
})
}
or you can write a common onChange function like this:
<input
...
value={this.state.userDetails.firstName}
onChange={(e) => {this.onChange(e.target.value, 'firstName')}}
/>
<input
...
value={this.state.userDetails.lastName}
onChange={(e) => {this.onChange(e.target.value, 'lastName')}}
/>
<input
...
value={this.state.userDetails.email}
onChange={(e) => {this.onChange(e.target.value, 'email')}}
/>
onChange(value, key) {
this.setState((previousState) => {
const userDetails = previousState.userDetails
return { userDetails: {...userDetails, [key]: value} }
})
}

Testing react form - AssertionError

I'm trying to test a click on a react component that renders a form, however it fails the third test with the following error
AssertionError: expected [Function: proxy] to have a property 'callCount' of 1, but got 0
Here's the test i wrote:
form.test.js
describe('<Form />', () => {
it('renders without exploding', () => {
shallow(<Form />);
});
it('renders an `.login_form`', () => {
const wrapper = shallow(<Form />);
expect(wrapper.find('.login_form')).to.have.length(1);
});
it('simulates click events', () => {
const onButtonClick = sinon.spy();
const wrapper = shallow(
<Form handleSubmit={ onButtonClick } />,
);
wrapper.find('.submitBtn').simulate('click');
expect(onButtonClick).to.have.property('callCount', 1);
});
});
and the component itself:
form.jsx
function Form(props) {
return (
<form onSubmit={ props.handleSubmit } className='form-horizontal login_form'>
<div className='form-group'>
<div className='col-md-offset-4 col-md-4 col-xs-12'>
<input className='form-control' type='text' id='username' value={ props.username } onChange={ props.handleUsername } placeholder='Username' required />
</div>
</div>
<div className='form-group'>
<div className='col-md-offset-4 col-md-4 col-xs-12'>
<input className='form-control' type='password' id='password' value={ props.password } onChange={ props.handlePassword } placeholder='Password' required />
</div>
</div>
<div className='form-group'>
<div className='col-md-offset-4 col-md-4 col-xs-12'>
<button className='btn btn-block btn-default submit submitBtn' type='submit'>Log in</button>
{
props.error !== '' &&
<p className='login_error no-margin'>
{props.error}
</p>
}
</div>
</div>
</form>
);
}
Form.propTypes = {
username: React.PropTypes.string,
password: React.PropTypes.string,
error: React.PropTypes.string,
handleUsername: React.PropTypes.func,
handlePassword: React.PropTypes.func,
handleSubmit: React.PropTypes.func,
};
export default Form;
What i am trying to do here is that i want to test that when the login button is clicked, the onSubmit handler is called. What am i doing on here?
Try to submit form this way:
wrapper.find("form").simulate("submit");

Resources