Key Bind to Snapshot Again Jest

Testing with Jest and Enzyme in React — Part 6 (Snapshot Testing in Jest)

In the previous tutorials, we learned the basic concepts of Jest and Enzyme. In here, I will explain another one of the popular ways of testing known as Snapshot Testing in Jest.

Before moving on with this, I recommend yous to take the projection named "testing-demo-app", which we used in previous tutorials. You tin can observe information technology in the below link.

What is Snapshot Testing?

  • Nosotros know that a Snapshot is a photograph which has taken quickly. We tin accept this kind of a snapshot, for a React component too.
  • Presume I took a snapshot of a React component yesterday. It consists of 2 <label>s and 2 <input>s. Today I am adding another <label> to the component. (Now birthday three <labels>)
  • Now the snapshot we took yesterday is different from what we have today as the component. If we compare these two (the snapshot and the component) nosotros can find where the difference occurs.
  • This technique provides by Jest, to compare components with their snapshots, is known as Snapshot Testing in Jest.

How to exercise Snapshot Testing in Jest?

Step 1 — Write a test (Modify Form.examination.js file) and run

  • Open the project binder and become to testing-demo-app/examination folder and modify Class.test.js file with the following content. (Check the content in bold letters)
          import Grade from '../src/components/Form';

allow wrapper;

beforeEach(() => {
wrapper = shallow(<Class/>);
});

describe('<Course /> rendering', () => {
information technology('renders correctly', () => {
expect(wrapper).toMatchSnapshot();
});

it('should return one <form>', () => {
expect(wrapper.find('class')).toHaveLength(1);
});

it('should not render any <push> when operator is not passed in props', () => {
expect(wrapper.detect('button')).toHaveLength(0);
});

it('should return 2 <label>s', () => {
look(wrapper.notice('label')).toHaveLength(2);
});

it('should render 2 <input>south', () => {
expect(wrapper.find('input')).toHaveLength(2);
});

it('should return ane <button> to Add when operator \'+\' is passed in props', () => {
wrapper.setProps({ operator: '+' } );
expect(wrapper.detect('#formButtonAdd')).toHaveLength(1);
await(wrapper.find('#formButtonSubtract')).toHaveLength(0);
});

it('should render one <button> to Subtract when operator \'-\' is passed in props', () => {
wrapper.setProps({ operator: '-' } );
expect(wrapper.notice('#formButtonAdd')).toHaveLength(0);
expect(wrapper.discover('#formButtonSubtract')).toHaveLength(one);
});
});

draw('<Form /> interactions', () => {
it('should change the state firstNumber when onChange function of the #number1 input is invoked', () => {
wrapper.discover('#number1').simulate('change',
{ target: { value: 50 } }
);
expect(wrapper.country('firstNumber')).toEqual(l);
expect(wrapper.state('secondNumber')).toEqual('');
});

it('should change the state secondNumber when onChange function of the #number2 input is invoked', () => {
wrapper.find('#number2').simulate('change',
{ target: { value: 60 } }
);
expect(wrapper.state('secondNumber')).toEqual(threescore);
expect(wrapper.state('firstNumber')).toEqual('');
});

it('should phone call the onClick function when \'Add\' push is clicked when the operator is \'+\'', () => {
wrapper.setProps({ operator: '+' } );
const mockedHandleClickAdd = jest.fn();
wrapper.case().handleAdd = mockedHandleClickAdd;
wrapper.find('#formButtonAdd').props().onClick();
expect(mockedHandleClickAdd).toHaveBeenCalledTimes(i);
});

information technology('should phone call the onClick function when \'Subtract\' push button is clicked when the operator is \'-\'', () => {
wrapper.setProps({ operator: '-' } );
const mockedHandleClickSubtract = jest.fn();
wrapper.example().handleSubtract = mockedHandleClickSubtract;
wrapper.discover('#formButtonSubtract').props().onClick();
await(mockedHandleClickSubtract).toHaveBeenCalledTimes(1);
});
});

draw('<Form /> lifecycle method invocations', () => {
it('should change the country componentState componentDidMount method is invoked', () => {
wait(wrapper.state('componentState')).toEqual('mounted');
});
});

  • Now, open a terminal within the projection directory and run the test by typing the post-obit.
          npm test Form.test.js        
  • Post-obit output should be displayed.
  • Yous can run across information technology says 1 Snapshot is passed, which means the Snapshot of <Grade> matches with the electric current component when rendering.
  • Now cheque the folder construction of your project. You must find a new folder created named as __snapshots__ under testing-demo-app/test, which stores the snapshots of the components.

  • The snapshot of <Form> which is Class.exam.js.snap should look like below.
          // Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<Course /> rendering renders correctly 1`] = `
ShallowWrapper {
Symbol(enzyme.__root__): [Circular],
Symbol(enzyme.__unrendered__): <Form />,
Symbol(enzyme.__renderer__): Object {
"batchedUpdates": [Function],
"getNode": [Part],
"render": [Function],
"simulateError": [Function],
"simulateEvent": [Function],
"unmount": [Function],
},
Symbol(enzyme.__node__): Object {
"case": nil,
"primal": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
<fieldset
className="class-group"
>
<label
className="grade-label"
>
Starting time Number:
</label>
<input
className="form-input"
id="number1"
onChange={[Function]}
blazon="text"
value=""
/>
</fieldset>,
<fieldset
className="class-group"
>
<label
className="form-label"
>
2d Number:
</characterization>
<input
className="form-input"
id="number2"
onChange={[Role]}
type="text"
value=""
/>
</fieldset>,
<div
className="grade-group"
/>,
],
"className": "grade-grouping",
},
"ref": null,
"rendered": Array [
Object {
"example": null,
"central": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
<label
className="form-characterization"
>
First Number:
</label>,
<input
className="class-input"
id="number1"
onChange={[Role]}
type="text"
value=""
/>,
],
"className": "grade-group",
},
"ref": nix,
"rendered": Array [
Object {
"example": null,
"cardinal": undefined,
"nodeType": "host",
"props": Object {
"children": "First Number:",
"className": "class-label",
},
"ref": null,
"rendered": "First Number:",
"type": "label",
},
Object {
"instance": goose egg,
"key": undefined,
"nodeType": "host",
"props": Object {
"className": "form-input",
"id": "number1",
"onChange": [Function],
"type": "text",
"value": "",
},
"ref": null,
"rendered": null,
"type": "input",
},
],
"blazon": "fieldset",
},
Object {
"case": null,
"key": undefined,
"nodeType": "host",
"props": Object {
"children": Assortment [
<label
className="form-label"
>
Second Number:
</label>,
<input
className="form-input"
id="number2"
onChange={[Function]}
type="text"
value=""
/>,
],
"className": "grade-grouping",
},
"ref": nada,
"rendered": Array [
Object {
"instance": null,
"central": undefined,
"nodeType": "host",
"props": Object {
"children": "Second Number:",
"className": "form-label",
},
"ref": zilch,
"rendered": "Second Number:",
"type": "label",
},
Object {
"example": null,
"central": undefined,
"nodeType": "host",
"props": Object {
"className": "course-input",
"id": "number2",
"onChange": [Function],
"blazon": "text",
"value": "",
},
"ref": null,
"rendered": null,
"type": "input",
},
],
"type": "fieldset",
},
Object {
"example": null,
"central": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
false,
false,
],
"className": "form-grouping",
},
"ref": null,
"rendered": Assortment [
false,
false,
],
"blazon": "div",
},
],
"blazon": "form",
},
Symbol(enzyme.__nodes__): Array [
Object {
"example": cipher,
"key": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
<fieldset
className="form-group"
>
<label
className="form-characterization"
>
First Number:
</label>
<input
className="form-input"
id="number1"
onChange={[Function]}
type="text"
value=""
/>
</fieldset>,
<fieldset
className="class-grouping"
>
<label
className="class-label"
>
2d Number:
</characterization>
<input
className="form-input"
id="number2"
onChange={[Function]}
type="text"
value=""
/>
</fieldset>,
<div
className="form-grouping"
/>,
],
"className": "form-group",
},
"ref": null,
"rendered": Assortment [
Object {
"example": null,
"fundamental": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
<label
className="form-characterization"
>
Outset Number:
</characterization>,
<input
className="form-input"
id="number1"
onChange={[Function]}
blazon="text"
value=""
/>,
],
"className": "form-grouping",
},
"ref": null,
"rendered": Assortment [
Object {
"instance": null,
"key": undefined,
"nodeType": "host",
"props": Object {
"children": "First Number:",
"className": "grade-label",
},
"ref": null,
"rendered": "Get-go Number:",
"type": "label",
},
Object {
"instance": null,
"key": undefined,
"nodeType": "host",
"props": Object {
"className": "form-input",
"id": "number1",
"onChange": [Function],
"type": "text",
"value": "",
},
"ref": aught,
"rendered": null,
"type": "input",
},
],
"blazon": "fieldset",
},
Object {
"instance": null,
"fundamental": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
<label
className="form-label"
>
2nd Number:
</characterization>,
<input
className="form-input"
id="number2"
onChange={[Function]}
type="text"
value=""
/>,
],
"className": "form-group",
},
"ref": zip,
"rendered": Array [
Object {
"instance": null,
"key": undefined,
"nodeType": "host",
"props": Object {
"children": "Second Number:",
"className": "course-label",
},
"ref": zip,
"rendered": "Second Number:",
"blazon": "label",
},
Object {
"example": null,
"key": undefined,
"nodeType": "host",
"props": Object {
"className": "form-input",
"id": "number2",
"onChange": [Function],
"type": "text",
"value": "",
},
"ref": null,
"rendered": zip,
"blazon": "input",
},
],
"blazon": "fieldset",
},
Object {
"instance": null,
"primal": undefined,
"nodeType": "host",
"props": Object {
"children": Array [
false,
faux,
],
"className": "class-group",
},
"ref": null,
"rendered": Assortment [
faux,
false,
],
"type": "div",
},
],
"type": "form",
},
],
Symbol(enzyme.__options__): Object {
"adapter": ReactSixteenAdapter {
"options": Object {
"enableComponentDidUpdateOnSetState": true,
"lifecycles": Object {
"componentDidUpdate": Object {
"onSetState": true,
},
"getDerivedStateFromProps": truthful,
"getSnapshotBeforeUpdate": truthful,
"setState": Object {
"skipsComponentDidUpdateOnNullish": true,
},
},
},
},
},
}
`;

Pace 2 — Alter a component and check

  • Now change Class.js in testing-demo-app/src/components with the following content. (Cheque the content in bold messages)
          import React, { Component } from 'react';

class Form extends Component {

constructor(props) {
super(props);
this.country = {
firstNumber: '',
secondNumber: '',
componentState:'default'
};

this.handleFirstNumber = this.handleFirstNumber.bind(this);
this.handleSecondNumber = this.handleSecondNumber.bind(this);
}

componentDidMount() {
this.setState({ componentState: 'mounted' });
}

handleFirstNumber(event) {
this.setState({ firstNumber: event.target.value });
}

handleSecondNumber(event) {
this.setState({ secondNumber: effect.target.value });
}

handleAdd(){
const { firstNumber, secondNumber } = this.state;
this.displayResult(parseInt(firstNumber) + parseInt(secondNumber))
}

handleSubtract(){
const { firstNumber, secondNumber } = this.state;
this.displayResult(parseInt(firstNumber) - parseInt(secondNumber))

}

displayResult(result){
alert(result);
}

return() {
const { firstNumber, secondNumber } = this.state;
const { operator } = this.props;
return (
<form className='course-grouping'>
<fieldset className='grade-group'>
<label className='form-characterization'>
1st Number:
</label>
<input type="text" id="number1" className='class-input' value={firstNumber} onChange={this.handleFirstNumber}/>
</fieldset>
<fieldset className='form-group'>
<label className='form-characterization'>
2d Number:
</characterization>
<input blazon="text" id="number2" className='grade-input' value={secondNumber} onChange={this.handleSecondNumber}/>
</fieldset>
<div className='form-group'>
{operator === '+' &&
<push button id='formButtonAdd' className='btn' type="button" onClick={() => this.handleAdd()}>Add together</button>
}
{operator === '-' &&
<push id='formButtonSubtract' className='btn' type="button" onClick={() => this.handleSubtract()}>Subtract</push button>
}
</div>
</course>
);
}

}

consign default Class;

  • I accept simply changed the texts of the <characterization>southward.
  • Now run the test again. The exam should fail like beneath.
  • You tin see that Jest shows the where the differences occurred when comparing the snapshot and the rendered component.

Step iii — Update Snapshots

  • In the previous step, our snapshot test failed.
  • If the changes nosotros did to Form.js is applicable, then we must update the snapshot according to the change which we did.
  • But just type the post-obit to update the snapshots.
          ./node_modules/.bin/jest --updateSnapshot        
  • You tin can see 1 Snapshot is updated, and all the tests have been passed.

Decision

With this tutorial, I would like to conclude this tutorial series on "Testing with Jest and Enzyme in React".

You tin can discover the work nosotros did in this tutorial in the branch named tutorial-06 in the below git repository.

I think now you accept a clear thought on what the UI testing means? I thought to write this tutorial series to share my experience and problems which I faced when I was doing testing in a React project. Hope this helped you guys too!

Cheers and Goodbye until adjacent fourth dimension!

Previous Tutorials

khullsomearesove46.blogspot.com

Source: https://wasuradananjith.medium.com/testing-with-jest-and-enzyme-in-react-part-6-snapshot-testing-in-jest-72fb0ce91c5a

0 Response to "Key Bind to Snapshot Again Jest"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel