Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing onChange function in Jest

I'm relatively new to Jest and testing in general. I have a component with an input element:

import * as React from "react";  export interface inputProps{     placeholder: string;     className: string;     value: string;     onSearch: (depID: string) => void; }  onSearch(event: any){     event.preventDefault();     //the actual onclick event is in another Component     this.props.onSearch(event.target.value.trim()); }  export class InputBox extends React.Component<inputProps, searchState> {   render() {         return (             <input                 onChange={this.onSearch} //need to test this                 className={this.props.className}                  type="text"                 value={this.props.value}                 placeholder={this.props.placeholder} />         );     } } 

I want a test that checks that input element's onChange is a function that takes in the input element's value attribute as the parameter. This is how far I have gotten so far:

//test to see the input element's onchange  //returns a function that takes its value as a param it("onChange param is the same value as the input value", () => {     const mockFn = jest.fn();     const input = enzyme.shallow(<InputBox                                      value="TestVal"                                     placeholder=""                                      className=""                                      onSearch={mockFn}/>);          input.find('input').simulate('change',  { preventDefault() {} });        expect(mockFn.mock.calls).toBe("TestVal");     }); 

I am going off of the first solution here Simulate a button click in Jest And: https://facebook.github.io/jest/docs/en/mock-functions.html

Edit: Running the above throws the following error:

 TypeError: Cannot read property 'value' of undefined 
like image 443
blankface Avatar asked Jan 10 '18 04:01

blankface


People also ask

How do you use onChange in react?

import React from "react"; function App() { return ( <input type="text" name="firstName" onChange={event => console. log("onchange is triggered")} /> ); } export default App; Now whenever you type something into the text box, React will trigger the function that we passed into the onChange prop.

What does onChange return?

An onChange event handler returns a Synthetic Event object which contains useful meta data such as the target input's id, name, and current value.

Can you test react with jest?

Jest is a JavaScript testing framework that allows developers to run tests on JavaScript and TypeScript code and can be easily integrated with React JS. Open the package. json, and you will find that when you use create-react-app for creating a react project, it has default support for jest and react testing library.


2 Answers

Syntax on your code snippet I think should be:

import React from 'react';  export default class InputBox extends React.Component {   onSearch(event) {     event.preventDefault();     this.props.onSearch(event.target.value.trim());   }   render () { return (<input onChange={this.onSearch.bind(this)} />); } } 

The test is failing because, as same you define the preventDefault function on the event object, you also must define other properties used on the onSearch function.

it('should call onChange prop', () => {   const onSearchMock = jest.fn();   const event = {     preventDefault() {},     target: { value: 'the-value' }   };   const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />);   component.find('input').simulate('change', event);   expect(onSearchMock).toBeCalledWith('the-value'); }); 

Previous test code needs to define the event shape because you are using shallow rendering. If you want instead to test that the actual input value is being used on your onSearch function you need to try a full render with enzyme.mount:

it('should call onChange prop with input value', () => {   const onSearchMock = jest.fn();   const component = enzyme.mount(<InputBox onSearch={onSearchMock} value="custom value" />);   component.find('input').simulate('change');   expect(onSearchMock).toBeCalledWith('custom value'); }); 
like image 98
Carloluis Avatar answered Sep 22 '22 23:09

Carloluis


For those testing using TypeScript (and borrowing from the answers above), you'll need to perform a type coercion (as React.ChangeEvent<HTMLInputElement>) to ensure that the linter can view the signature as being compatible:

React file

export class InputBox extends React.Component<inputProps, searchState> {   onSearch(event: React.ChangeEvent<HTMLInputElement>){     event.preventDefault();     //the actual onclick event is in another Component     this.props.onSearch(event.target.value.trim());   }    render() {     return (       <input         onChange={this.onSearch} //need to test this         className={this.props.className}          type="text"         value={this.props.value}         placeholder={this.props.placeholder} />       );   } } 

Test file

it('should call onChange prop', () => {   const onSearchMock = jest.fn();   const event = {     target: { value: 'the-value' }   } as React.ChangeEvent<HTMLInputElement>;   const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />);   component.find('input').simulate('change', event);   expect(onSearchMock).toBeCalledWith('the-value'); }); 

or alternatively

it('should call onChange prop', () => {   const onSearchMock = jest.fn();   const event = {     target: { value: 'the-value' }   } as React.ChangeEvent<HTMLInputElement>;   const component = enzyme.mount<InputBox>(<InputBox onSearch={onSearchMock} />);   const instance = component.instance();   instance.onSearch(event);   expect(onSearchMock).toBeCalledWith('the-value'); }); 
like image 21
FrostyDog Avatar answered Sep 24 '22 23:09

FrostyDog