SlideShare a Scribd company logo
1 of 39
Download to read offline
Jannaeé Sick
Crushing React Bugs with
Jest and Enzyme
An introduction into unit testing
1
This talk is for those...
Build React Components
New or interested in getting started with unit
testing
2
About Me
Front End developer at IBM on
the Red Hat Marketplace team.
3
About Me
Facts:
ZERO experience with unit
testing before this year and
3% experience building
React Components
4
About Me
Facts:
ZERO experience with unit
testing before this year and
3% experience building
React Components
Huge learning year for me
5
Agenda
1. Importance of unit testing
2. Installation
3. Run our first test
6 . 1
6 . 2
6 . 3
What is Jest
JavaScript Testing Framework
Open source created by Facebook
Assert, snapshots, code coverage
reports...
6 . 4
What is Enzyme?
JavaScript Testing Utility
Open source created by AirBnB
Easily manipulate, traverse 
Can be used in conjunction with Jest
6 . 5
Setup
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re
1
2
3
4
///setupTest.js5
import Enzyme from 'enzyme';6
import Adapter from 'enzyme-adapter-react-16';7
Enzyme.configure({ adapter: new Adapter() });8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
6 . 6
Setup
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re
1
2
3
4
///setupTest.js5
import Enzyme from 'enzyme';6
import Adapter from 'enzyme-adapter-react-16';7
Enzyme.configure({ adapter: new Adapter() });8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
///setupTest.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast1
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2
3
4
5
6
7
8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
6 . 6
Setup
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re
1
2
3
4
///setupTest.js5
import Enzyme from 'enzyme';6
import Adapter from 'enzyme-adapter-react-16';7
Enzyme.configure({ adapter: new Adapter() });8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
///setupTest.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast1
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2
3
4
5
6
7
8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
// Can add configuration in package.json or a jest.config.js f
// package.json
{
"jest": {
"collectCoverage": true,
"coverageDirectory": "coverage",
"collectCoverageFrom": [
"src/components/**/*.{js,jsx,ts,tsx}"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
],
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"coverageReporters": [30
"text"31
],32
"coverageThreshold": {33
"global": {34
6 . 6
Setup
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re
1
2
3
4
///setupTest.js5
import Enzyme from 'enzyme';6
import Adapter from 'enzyme-adapter-react-16';7
Enzyme.configure({ adapter: new Adapter() });8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
///setupTest.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast1
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2
3
4
5
6
7
8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
// Can add configuration in package.json or a jest.config.js f18
// package.json19
{20
// Can add configuration in package.json or a jest.config.js f
// package.json
{
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast1
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2
3
4
///setupTest.js5
import Enzyme from 'enzyme';6
import Adapter from 'enzyme-adapter-react-16';7
Enzyme.configure({ adapter: new Adapter() });8
9
10
// Another option, make Enzyme functions available globally wi11
// global.React = React;12
// global.shallow = shallow;13
// global.render = render;14
// global.mount = mount;15
16
17
18
19
20
// https://github.com/FormidableLabs/enzyme-matchers/tree/mast
yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re
///setupTest.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });
// Another option, make Enzyme functions available globally wi
// global.React = React;
// global.shallow = shallow;
// global.render = render;
// global.mount = mount;
// Can add configuration in package.json or a jest.config.js f
// package.json
{
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
6 . 6
//ATOForm.js
import { Form, TextInput } from 'carbon-component
import React from 'react';
const ATOForm = () => {
return (
<Form className="someForm">
<h4 className="title">Our Test Subjec
<div style={{ marginBottom: '2rem' }}
<TextInput
id="test2"
invalidText="Invalid error me
labelText="First input field"
l h ld "Pl h ld t t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ATOForm.js
6 . 7
//ATOForm.js
import { Form, TextInput } from 'carbon-components-react';
import React from 'react';
const ATOForm = () => {
return (
<Form className="someForm">
<h4 className="title">Our Test Subject</h4>
<div style={{ marginBottom: '2rem' }}>
<TextInput
id="test2"
invalidText="Invalid error message."
labelText="First input field"
placeholder="Placeholder text"
/>
</div>
</Form>
)
}
export default ATOForm;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
6 . 8
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
1
2
3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
6 . 9
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
1
2
3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
describe( '<ATOForm /> rendering', () => {
} );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
19
6 . 9
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
1
2
3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
describe( '<ATOForm /> rendering', () => {
} );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
19
it( 'should render 1 form ', () => {
expect( wrapper ).toMatchSnapshot();
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
describe( '<ATOForm /> rendering', () => {6
7
8
const wrapper = shallow( <ATOForm /> );9
10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
6 . 9
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
1
2
3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
describe( '<ATOForm /> rendering', () => {
} );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
19
it( 'should render 1 form ', () => {
expect( wrapper ).toMatchSnapshot();
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
describe( '<ATOForm /> rendering', () => {6
7
8
const wrapper = shallow( <ATOForm /> );9
10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
import ATOForm from './ATOForm';
const wrapper = shallow( <ATOForm /> );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
6 . 9
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
1
2
3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
describe( '<ATOForm /> rendering', () => {
} );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
19
it( 'should render 1 form ', () => {
expect( wrapper ).toMatchSnapshot();
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
describe( '<ATOForm /> rendering', () => {6
7
8
const wrapper = shallow( <ATOForm /> );9
10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
import ATOForm from './ATOForm';
const wrapper = shallow( <ATOForm /> );
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
9
expect( wrapper ).toMatchSnapshot();10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
expect( wrapper ).toMatchSnapshot();
//ATOForm.test.js1
import React from 'react';2
import { shallow } from 'enzyme';3
import ATOForm from './ATOForm';4
5
describe( '<ATOForm /> rendering', () => {6
7
it( 'should render 1 form ', () => {8
const wrapper = shallow( <ATOForm /> );9
10
} );11
12
it( 'should render a title ', () => {13
const wrapper = shallow( <ATOForm /> );14
console.log(wrapper.debug());15
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16
} );17
18
} );19
6 . 9
//ATOForm.test.js
import React from 'react';
import { shallow } from 'enzyme';
import ATOForm from './ATOForm';
describe( '<ATOForm /> rendering', () => {
it( 'should render 1 form ', () => {
const wrapper = shallow( <ATOForm /> );
expect( wrapper ).toMatchSnapshot();
} );
it( 'should render a title ', () => {
const wrapper = shallow( <ATOForm /> );
console.log(wrapper.debug());
expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr
} );
} );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// yarn test --watch
PASS src/components/ATOForm/ATOForm.test.js
<ATOForm /> rendering
✓ should render 1 form (7ms)
✓ should render a title (3ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 1 passed, 1 total
Time: 4.306s
Ran all test suites related to changed files.
1
2
3
4
5
6
7
8
9
10
11
6 . 10
Snapshot Testing
//ATOForm.js
import { Form, TextInput } from 'carbon-components-react';
import React from 'react';
const ATOForm = () => {
return (
<Form className="someForm">
<h4 className="title">Our Test Subject</h4>
<div style={{ marginBottom: '2rem' }}>
<TextInput
id="test2"
invalidText="Invalid error message."
labelText="First input field"
placeholder="Placeholder text"
/>
</div>
</Form>
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// __snapshots__/ATOForm.test.js.snap
exports[`<ATOForm /> rendering should render 1 form 1`] = `
<Form
className="someForm"
>
<h4
className="title"
>
Our Test Subject
</h4>
<div
style={
Object {
"marginBottom": "2rem",
}
}
>
<ForwardRef(TextInput)
disabled={false}
helperText=""
id="test2"
inline={false}
invalid={false}
invalidText="Invalid error message."
labelText="First input field"
light={false}
onChange={[Function]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 6 . 11
Snapshot Testing
//ATOForm.js
import { Form, TextInput } from 'carbon-components-react';
import React from 'react';
const ATOForm = () => {
return (
<Form className="someForm">
<h4 className="title">Our Test Subject</h4>
<div style={{ marginBottom: '2rem' }}>
<TextInput
id="test2"
invalidText="Invalid error message."
labelText="First input field"
placeholder="Placeholder text"
/>
</div>
</Form>
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// __snapshots__/ATOForm.test.js.snap
exports[`<ATOForm /> rendering should render 1 form 1`] = `
<Form
className="someForm"
>
<h4
className="title"
>
Our Test Subject
</h4>
<div
style={
Object {
"marginBottom": "2rem",
}
}
>
<ForwardRef(TextInput)
disabled={false}
helperText=""
id="test2"
inline={false}
invalid={false}
invalidText="Invalid error message."
labelText="First input field"
light={false}
onChange={[Function]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// __snapshots__/ATOForm.test.js.snap
exports[`<ATOForm /> rendering should render 1 form 1`] = `
<Form
className="someForm"
>
<h4
className="title"
>
Our Test Subject
</h4>
<div
style={
Object {
"marginBottom": "2rem",
}
}
>
<ForwardRef(TextInput)
disabled={false}
helperText=""
id="test2"
inline={false}
invalid={false}
invalidText="Invalid error message."
labelText="First input field"
light={false}
onChange={[Function]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 6 . 11
Snapshot Testing
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
Our Test Subject10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
6 . 12
Snapshot Testing
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
Our Test Subject10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
Our Test Subject
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
6 . 12
Snapshot Testing
Our Test Subject
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
6 . 13
Snapshot Testing
Our Test Subject
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
// __snapshots__/ATOForm.test.js.snap
exports[`<ATOForm /> rendering should render
<Form
className="someForm"
>
<h4
className="title"
>
Our Test Subject
</h4>
<div
style={
Object {
"marginBottom": "2rem",
}
}
>
<ForwardRef(TextInput)
disabled={false}
helperText=""
id="test2"
inline={false}
invalid={false}
invalidText="Invalid error message."
labelText="First input field"
light={false}
onChange={[Function]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
6 . 13
Snapshot Testing Fail
Our Test Subject
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
FAIL src/components/ATOForm/ATOForm.test.js
<ATOForm /> rendering
✓ should render 1 form (5ms)
✕ should render a title (5ms)
● <ATOForm /> rendering › should render a title
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
19 | it( 'should render a title ', () => {
20 | const wrapper = shallow( <ATOForm /> );
> 21 | expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe
| ^
22 | } );
23 | } );
at Object.<anonymous> (src/components/ATOForm/ATOForm.test.js:21:73)
› 1 snapshot updated.
Snapshot Summary
› 1 snapshot updated from 1 test suite.
Test Suites: 1 failed, 1 total
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 6 . 14
Snapshot Testing Fail
Our Test Subject
// __snapshots__/ATOForm.test.js.snap1
2
exports[`<ATOForm /> rendering should render3
<Form4
className="someForm"5
>6
<h47
className="title"8
>9
10
</h4>11
<div12
style={13
Object {14
"marginBottom": "2rem",15
}16
}17
>18
<ForwardRef(TextInput)19
disabled={false}20
helperText=""21
id="test2"22
inline={false}23
invalid={false}24
invalidText="Invalid error message."25
labelText="First input field"26
light={false}27
onChange={[Function]}28
// __snapshots__/ATOForm.test.js.snap
exports[`<ATOForm /> rendering should render
<Form
className="someForm"
>
<h4
className="title"
>
Our Test Subject
</h4>
<div
style={
Object {
"marginBottom": "2rem",
}
}
>
<ForwardRef(TextInput)
disabled={false}
helperText=""
id="test2"
inline={false}
invalid={false}
invalidText="Invalid error message."
labelText="First input field"
light={false}
onChange={[Function]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<h4 className="title">Our Subject</h4>
//ATOForm.js1
import { Form, TextInput } from 'carbon-components-react';2
import React from 'react';3
4
const ATOForm = () => {5
return (6
<Form className="someForm">7
8
<div style={{ marginBottom: '2rem' }}>9
<TextInput10
id="test2"11
invalidText="Invalid error message."12
labelText="First input field"13
placeholder="Placeholder text"14
/>15
</div>16
</Form>17
18
)19
FAIL src/components/ATOForm/ATOForm.test.js
<ATOForm /> rendering
✓ should render 1 form (5ms)
✕ should render a title (5ms)
● <ATOForm /> rendering › should render a title
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
19 | it( 'should render a title ', () => {
20 | const wrapper = shallow( <ATOForm /> );
> 21 | expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe
| ^
22 | } );
23 | } );
at Object.<anonymous> (src/components/ATOForm/ATOForm.test.js:21:73)
› 1 snapshot updated.
Snapshot Summary
› 1 snapshot updated from 1 test suite.
Test Suites: 1 failed, 1 total
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 6 . 14
Coverage reports
PASS src/components/Launch/Launch.test.js
PASS src/components/ATOForm/ATOForm.test.js
------------|----------|----------|----------|----------
File | % Stmts | % Branch | % Funcs | % Lines
------------|----------|----------|----------|----------
All files | 100 | 0 | 100 | 100
ATOForm.js | 100 | 0 | 100 | 100
------------|----------|----------|----------|----------
Test Suites: 2 passed, 2 total
Tests: 4 passed, 4 total
S h t 2 d 2 t t l
1
2
3
4
5
6
7
8
9
10
11
12
6 . 15
6 . 16
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
} )14
} );15
6 . 17
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
} )14
} );15
describe( '<Launch /> interactions', () => {
} )
Lauch.js1
2
3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
14
} );15
6 . 17
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
} )14
} );15
describe( '<Launch /> interactions', () => {
} )
Lauch.js1
2
3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
14
} );15
it( 'should open Launch Modal when clicked', () => {
const wrapper = mount( <Launch /> );
const button = wrapper.find('button');
button.at(0).simulate('click');
} )
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
6
7
8
9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
14
} );15
6 . 17
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
} )14
} );15
describe( '<Launch /> interactions', () => {
} )
Lauch.js1
2
3
4
//Simulate DOM events or a click on the button5
it( 'should open Launch Modal when clicked', () => {6
const wrapper = mount( <Launch /> );7
const button = wrapper.find('button');8
button.at(0).simulate('click');9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
14
} );15
it( 'should open Launch Modal when clicked', () => {
const wrapper = mount( <Launch /> );
const button = wrapper.find('button');
button.at(0).simulate('click');
} )
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
6
7
8
9
10
//After inspecting the code, I can see this is toggled to visible one clicked11
const modalDiv = wrapper.find('div#input-modal');12
expect(modalDiv.hasClass('is-visible')).toBe(true);13
14
} );15
it( 'should open Launch Modal when clicked', () => {
const wrapper = mount( <Launch /> );
const button = wrapper.find('button');
button.at(0).simulate('click');
//After inspecting the code, I can see this is toggled to visible one clicked
const modalDiv = wrapper.find('div#input-modal');
expect(modalDiv.hasClass('is-visible')).toBe(true);
Lauch.js1
2
describe( '<Launch /> interactions', () => {3
4
//Simulate DOM events or a click on the button5
6
7
8
9
10
11
12
13
} )14
} );15
6 . 17
Testing
without
committing
https://codesandbox.io/embed/github/kentcdodd
s/react-testing-library-examples/tree/master/?
fontsize=14&hidenavigation=1&theme=dark
6 . 18
“  
Keep your code organized
with 'describe' and 'it' blocks.
--
Sometimes testing can take just as long as
writing the component, if not longer.
--
Don't be afraid to refactor your
code to make the test work.
--
Writing tests will help you to gain a broad
understanding of your codebase. Also help you
to become a better programmer.
“  
6 . 19
Thank you for joining
Crushing React Bugs with Jest and Enyme
@jannaeesick
References:
  , , ,
,  
,
,
 
 
 
Jest Enzyme Carbon Design System How to read Test
Coverage report generated using Jest. React function
components with Hooks Testing with Jest and Enzyme in
React — Part 3 (Best Practices when testing with Jest and
Enzyme) Red Hat Marketplace
link to this code6 . 20

More Related Content

What's hot

The State of PHPUnit
The State of PHPUnitThe State of PHPUnit
The State of PHPUnit
Edorian
 
Error xaction etl_ktr
Error xaction etl_ktrError xaction etl_ktr
Error xaction etl_ktr
hurac
 

What's hot (20)

Appium Automation with Kotlin
Appium Automation with KotlinAppium Automation with Kotlin
Appium Automation with Kotlin
 
The State of PHPUnit
The State of PHPUnitThe State of PHPUnit
The State of PHPUnit
 
Endevor api an introduction to the endevor application programming interface
Endevor api   an introduction to the endevor application programming interface Endevor api   an introduction to the endevor application programming interface
Endevor api an introduction to the endevor application programming interface
 
The State of PHPUnit
The State of PHPUnitThe State of PHPUnit
The State of PHPUnit
 
Agile mobile
Agile mobileAgile mobile
Agile mobile
 
Performance Analysis and Monitoring with Perf4j
Performance Analysis and Monitoring with Perf4jPerformance Analysis and Monitoring with Perf4j
Performance Analysis and Monitoring with Perf4j
 
Ten common mistakes made in Function Java - iSense Java Summit
Ten common mistakes made in Function Java - iSense Java SummitTen common mistakes made in Function Java - iSense Java Summit
Ten common mistakes made in Function Java - iSense Java Summit
 
Kirill Rozin - Practical Wars for Automatization
Kirill Rozin - Practical Wars for AutomatizationKirill Rozin - Practical Wars for Automatization
Kirill Rozin - Practical Wars for Automatization
 
Testing Guide
Testing GuideTesting Guide
Testing Guide
 
Ten common mistakes made in Function Java
Ten common mistakes made in Function JavaTen common mistakes made in Function Java
Ten common mistakes made in Function Java
 
Alfresco study presentation 38th customize How-To WebDAV
Alfresco study presentation 38th customize How-To WebDAVAlfresco study presentation 38th customize How-To WebDAV
Alfresco study presentation 38th customize How-To WebDAV
 
Annotation processing
Annotation processingAnnotation processing
Annotation processing
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Супер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOSСупер быстрая автоматизация тестирования на iOS
Супер быстрая автоматизация тестирования на iOS
 
Php 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php beneluxPhp 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php benelux
 
Apache cheat sheet
Apache cheat sheetApache cheat sheet
Apache cheat sheet
 
Error xaction etl_ktr
Error xaction etl_ktrError xaction etl_ktr
Error xaction etl_ktr
 
Alfresco study37 alfresco_ng2_components
Alfresco study37 alfresco_ng2_componentsAlfresco study37 alfresco_ng2_components
Alfresco study37 alfresco_ng2_components
 
Flask SQLAlchemy
Flask SQLAlchemy Flask SQLAlchemy
Flask SQLAlchemy
 
Agile Android
Agile AndroidAgile Android
Agile Android
 

Similar to Crushing React bugs with Jest and Enzyme

Node.js basics
Node.js basicsNode.js basics
Node.js basics
Ben Lin
 
Question IYou are going to use the semaphores for process sy.docx
Question IYou are going to use the semaphores for process sy.docxQuestion IYou are going to use the semaphores for process sy.docx
Question IYou are going to use the semaphores for process sy.docx
audeleypearl
 

Similar to Crushing React bugs with Jest and Enzyme (20)

Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Workshop React.js
Workshop React.jsWorkshop React.js
Workshop React.js
 
Maze
MazeMaze
Maze
 
Node.js basics
Node.js basicsNode.js basics
Node.js basics
 
Ultimate Survival - React-Native edition
Ultimate Survival - React-Native editionUltimate Survival - React-Native edition
Ultimate Survival - React-Native edition
 
Spring hibernate jsf_primefaces_intergration
Spring hibernate jsf_primefaces_intergrationSpring hibernate jsf_primefaces_intergration
Spring hibernate jsf_primefaces_intergration
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech
はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_techはじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech
はじめて Phantom と遭遇して、闇雲に闘いを挑んでみた話 #kbkz_tech
 
Automated Java Deployments With Rpm
Automated Java Deployments With RpmAutomated Java Deployments With Rpm
Automated Java Deployments With Rpm
 
Question IYou are going to use the semaphores for process sy.docx
Question IYou are going to use the semaphores for process sy.docxQuestion IYou are going to use the semaphores for process sy.docx
Question IYou are going to use the semaphores for process sy.docx
 
Jasmine with JS-Test-Driver
Jasmine with JS-Test-DriverJasmine with JS-Test-Driver
Jasmine with JS-Test-Driver
 
Lecture: Webpack 4
Lecture: Webpack 4Lecture: Webpack 4
Lecture: Webpack 4
 
How To Install Openbravo ERP 2.50 MP43 in Ubuntu
How To Install Openbravo ERP 2.50 MP43 in UbuntuHow To Install Openbravo ERP 2.50 MP43 in Ubuntu
How To Install Openbravo ERP 2.50 MP43 in Ubuntu
 
Ch ch-changes cake php2
Ch ch-changes cake php2Ch ch-changes cake php2
Ch ch-changes cake php2
 
Frontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the likeFrontend JS workflow - Gulp 4 and the like
Frontend JS workflow - Gulp 4 and the like
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and Friends
 
A few good JavaScript development tools
A few good JavaScript development toolsA few good JavaScript development tools
A few good JavaScript development tools
 
RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
 
Capistrano
CapistranoCapistrano
Capistrano
 
Spring into rails
Spring into railsSpring into rails
Spring into rails
 

More from All Things Open

Open Source and Public Policy
Open Source and Public PolicyOpen Source and Public Policy
Open Source and Public Policy
All Things Open
 
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
All Things Open
 
How to Write & Deploy a Smart Contract
How to Write & Deploy a Smart ContractHow to Write & Deploy a Smart Contract
How to Write & Deploy a Smart Contract
All Things Open
 
Scaling Web Applications with Background
Scaling Web Applications with BackgroundScaling Web Applications with Background
Scaling Web Applications with Background
All Things Open
 
Build Developer Experience Teams for Open Source
Build Developer Experience Teams for Open SourceBuild Developer Experience Teams for Open Source
Build Developer Experience Teams for Open Source
All Things Open
 
Sudo – Giving access while staying in control
Sudo – Giving access while staying in controlSudo – Giving access while staying in control
Sudo – Giving access while staying in control
All Things Open
 
Fortifying the Future: Tackling Security Challenges in AI/ML Applications
Fortifying the Future: Tackling Security Challenges in AI/ML ApplicationsFortifying the Future: Tackling Security Challenges in AI/ML Applications
Fortifying the Future: Tackling Security Challenges in AI/ML Applications
All Things Open
 
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
All Things Open
 

More from All Things Open (20)

Building Reliability - The Realities of Observability
Building Reliability - The Realities of ObservabilityBuilding Reliability - The Realities of Observability
Building Reliability - The Realities of Observability
 
Modern Database Best Practices
Modern Database Best PracticesModern Database Best Practices
Modern Database Best Practices
 
Open Source and Public Policy
Open Source and Public PolicyOpen Source and Public Policy
Open Source and Public Policy
 
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
Weaving Microservices into a Unified GraphQL Schema with graph-quilt - Ashpak...
 
The State of Passwordless Auth on the Web - Phil Nash
The State of Passwordless Auth on the Web - Phil NashThe State of Passwordless Auth on the Web - Phil Nash
The State of Passwordless Auth on the Web - Phil Nash
 
Total ReDoS: The dangers of regex in JavaScript
Total ReDoS: The dangers of regex in JavaScriptTotal ReDoS: The dangers of regex in JavaScript
Total ReDoS: The dangers of regex in JavaScript
 
What Does Real World Mass Adoption of Decentralized Tech Look Like?
What Does Real World Mass Adoption of Decentralized Tech Look Like?What Does Real World Mass Adoption of Decentralized Tech Look Like?
What Does Real World Mass Adoption of Decentralized Tech Look Like?
 
How to Write & Deploy a Smart Contract
How to Write & Deploy a Smart ContractHow to Write & Deploy a Smart Contract
How to Write & Deploy a Smart Contract
 
Spinning Your Drones with Cadence Workflows, Apache Kafka and TensorFlow
 Spinning Your Drones with Cadence Workflows, Apache Kafka and TensorFlow Spinning Your Drones with Cadence Workflows, Apache Kafka and TensorFlow
Spinning Your Drones with Cadence Workflows, Apache Kafka and TensorFlow
 
DEI Challenges and Success
DEI Challenges and SuccessDEI Challenges and Success
DEI Challenges and Success
 
Scaling Web Applications with Background
Scaling Web Applications with BackgroundScaling Web Applications with Background
Scaling Web Applications with Background
 
Supercharging tutorials with WebAssembly
Supercharging tutorials with WebAssemblySupercharging tutorials with WebAssembly
Supercharging tutorials with WebAssembly
 
Using SQL to Find Needles in Haystacks
Using SQL to Find Needles in HaystacksUsing SQL to Find Needles in Haystacks
Using SQL to Find Needles in Haystacks
 
Configuration Security as a Game of Pursuit Intercept
Configuration Security as a Game of Pursuit InterceptConfiguration Security as a Game of Pursuit Intercept
Configuration Security as a Game of Pursuit Intercept
 
Scaling an Open Source Sponsorship Program
Scaling an Open Source Sponsorship ProgramScaling an Open Source Sponsorship Program
Scaling an Open Source Sponsorship Program
 
Build Developer Experience Teams for Open Source
Build Developer Experience Teams for Open SourceBuild Developer Experience Teams for Open Source
Build Developer Experience Teams for Open Source
 
Deploying Models at Scale with Apache Beam
Deploying Models at Scale with Apache BeamDeploying Models at Scale with Apache Beam
Deploying Models at Scale with Apache Beam
 
Sudo – Giving access while staying in control
Sudo – Giving access while staying in controlSudo – Giving access while staying in control
Sudo – Giving access while staying in control
 
Fortifying the Future: Tackling Security Challenges in AI/ML Applications
Fortifying the Future: Tackling Security Challenges in AI/ML ApplicationsFortifying the Future: Tackling Security Challenges in AI/ML Applications
Fortifying the Future: Tackling Security Challenges in AI/ML Applications
 
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
Securing Cloud Resources Deployed with Control Planes on Kubernetes using Gov...
 

Recently uploaded

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Recently uploaded (20)

Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 

Crushing React bugs with Jest and Enzyme

  • 1. Jannaeé Sick Crushing React Bugs with Jest and Enzyme An introduction into unit testing 1
  • 2. This talk is for those... Build React Components New or interested in getting started with unit testing 2
  • 3. About Me Front End developer at IBM on the Red Hat Marketplace team. 3
  • 4. About Me Facts: ZERO experience with unit testing before this year and 3% experience building React Components 4
  • 5. About Me Facts: ZERO experience with unit testing before this year and 3% experience building React Components Huge learning year for me 5
  • 6. Agenda 1. Importance of unit testing 2. Installation 3. Run our first test 6 . 1
  • 9. What is Jest JavaScript Testing Framework Open source created by Facebook Assert, snapshots, code coverage reports... 6 . 4
  • 10. What is Enzyme? JavaScript Testing Utility Open source created by AirBnB Easily manipulate, traverse  Can be used in conjunction with Jest 6 . 5
  • 11. Setup // https://github.com/FormidableLabs/enzyme-matchers/tree/mast yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re 1 2 3 4 ///setupTest.js5 import Enzyme from 'enzyme';6 import Adapter from 'enzyme-adapter-react-16';7 Enzyme.configure({ adapter: new Adapter() });8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 6 . 6
  • 12. Setup // https://github.com/FormidableLabs/enzyme-matchers/tree/mast yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re 1 2 3 4 ///setupTest.js5 import Enzyme from 'enzyme';6 import Adapter from 'enzyme-adapter-react-16';7 Enzyme.configure({ adapter: new Adapter() });8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 ///setupTest.js import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); // https://github.com/FormidableLabs/enzyme-matchers/tree/mast1 yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2 3 4 5 6 7 8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 6 . 6
  • 13. Setup // https://github.com/FormidableLabs/enzyme-matchers/tree/mast yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re 1 2 3 4 ///setupTest.js5 import Enzyme from 'enzyme';6 import Adapter from 'enzyme-adapter-react-16';7 Enzyme.configure({ adapter: new Adapter() });8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 ///setupTest.js import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); // https://github.com/FormidableLabs/enzyme-matchers/tree/mast1 yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2 3 4 5 6 7 8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 // Can add configuration in package.json or a jest.config.js f // package.json { "jest": { "collectCoverage": true, "coverageDirectory": "coverage", "collectCoverageFrom": [ "src/components/**/*.{js,jsx,ts,tsx}" ], "snapshotSerializers": [ "enzyme-to-json/serializer" ], // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 "coverageReporters": [30 "text"31 ],32 "coverageThreshold": {33 "global": {34 6 . 6
  • 14. Setup // https://github.com/FormidableLabs/enzyme-matchers/tree/mast yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re 1 2 3 4 ///setupTest.js5 import Enzyme from 'enzyme';6 import Adapter from 'enzyme-adapter-react-16';7 Enzyme.configure({ adapter: new Adapter() });8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 ///setupTest.js import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); // https://github.com/FormidableLabs/enzyme-matchers/tree/mast1 yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2 3 4 5 6 7 8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 // Can add configuration in package.json or a jest.config.js f18 // package.json19 {20 // Can add configuration in package.json or a jest.config.js f // package.json { // https://github.com/FormidableLabs/enzyme-matchers/tree/mast1 yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re2 3 4 ///setupTest.js5 import Enzyme from 'enzyme';6 import Adapter from 'enzyme-adapter-react-16';7 Enzyme.configure({ adapter: new Adapter() });8 9 10 // Another option, make Enzyme functions available globally wi11 // global.React = React;12 // global.shallow = shallow;13 // global.render = render;14 // global.mount = mount;15 16 17 18 19 20 // https://github.com/FormidableLabs/enzyme-matchers/tree/mast yarn add jest-environment-enzyme jest-enzyme enzyme-adapter-re ///setupTest.js import Enzyme from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({ adapter: new Adapter() }); // Another option, make Enzyme functions available globally wi // global.React = React; // global.shallow = shallow; // global.render = render; // global.mount = mount; // Can add configuration in package.json or a jest.config.js f // package.json { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 6 . 6
  • 15. //ATOForm.js import { Form, TextInput } from 'carbon-component import React from 'react'; const ATOForm = () => { return ( <Form className="someForm"> <h4 className="title">Our Test Subjec <div style={{ marginBottom: '2rem' }} <TextInput id="test2" invalidText="Invalid error me labelText="First input field" l h ld "Pl h ld t t 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ATOForm.js 6 . 7
  • 16. //ATOForm.js import { Form, TextInput } from 'carbon-components-react'; import React from 'react'; const ATOForm = () => { return ( <Form className="someForm"> <h4 className="title">Our Test Subject</h4> <div style={{ marginBottom: '2rem' }}> <TextInput id="test2" invalidText="Invalid error message." labelText="First input field" placeholder="Placeholder text" /> </div> </Form> ) } export default ATOForm; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 6 . 8
  • 17. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; 1 2 3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 6 . 9
  • 18. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; 1 2 3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 describe( '<ATOForm /> rendering', () => { } ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 19 6 . 9
  • 19. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; 1 2 3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 describe( '<ATOForm /> rendering', () => { } ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 19 it( 'should render 1 form ', () => { expect( wrapper ).toMatchSnapshot(); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 describe( '<ATOForm /> rendering', () => {6 7 8 const wrapper = shallow( <ATOForm /> );9 10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 6 . 9
  • 20. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; 1 2 3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 describe( '<ATOForm /> rendering', () => { } ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 19 it( 'should render 1 form ', () => { expect( wrapper ).toMatchSnapshot(); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 describe( '<ATOForm /> rendering', () => {6 7 8 const wrapper = shallow( <ATOForm /> );9 10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 import ATOForm from './ATOForm'; const wrapper = shallow( <ATOForm /> ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 6 . 9
  • 21. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; 1 2 3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 describe( '<ATOForm /> rendering', () => { } ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 19 it( 'should render 1 form ', () => { expect( wrapper ).toMatchSnapshot(); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 describe( '<ATOForm /> rendering', () => {6 7 8 const wrapper = shallow( <ATOForm /> );9 10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 import ATOForm from './ATOForm'; const wrapper = shallow( <ATOForm /> ); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 9 expect( wrapper ).toMatchSnapshot();10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 expect( wrapper ).toMatchSnapshot(); //ATOForm.test.js1 import React from 'react';2 import { shallow } from 'enzyme';3 import ATOForm from './ATOForm';4 5 describe( '<ATOForm /> rendering', () => {6 7 it( 'should render 1 form ', () => {8 const wrapper = shallow( <ATOForm /> );9 10 } );11 12 it( 'should render a title ', () => {13 const wrapper = shallow( <ATOForm /> );14 console.log(wrapper.debug());15 expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr16 } );17 18 } );19 6 . 9
  • 22. //ATOForm.test.js import React from 'react'; import { shallow } from 'enzyme'; import ATOForm from './ATOForm'; describe( '<ATOForm /> rendering', () => { it( 'should render 1 form ', () => { const wrapper = shallow( <ATOForm /> ); expect( wrapper ).toMatchSnapshot(); } ); it( 'should render a title ', () => { const wrapper = shallow( <ATOForm /> ); console.log(wrapper.debug()); expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe(tr } ); } ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // yarn test --watch PASS src/components/ATOForm/ATOForm.test.js <ATOForm /> rendering ✓ should render 1 form (7ms) ✓ should render a title (3ms) Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 1 passed, 1 total Time: 4.306s Ran all test suites related to changed files. 1 2 3 4 5 6 7 8 9 10 11 6 . 10
  • 23. Snapshot Testing //ATOForm.js import { Form, TextInput } from 'carbon-components-react'; import React from 'react'; const ATOForm = () => { return ( <Form className="someForm"> <h4 className="title">Our Test Subject</h4> <div style={{ marginBottom: '2rem' }}> <TextInput id="test2" invalidText="Invalid error message." labelText="First input field" placeholder="Placeholder text" /> </div> </Form> ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // __snapshots__/ATOForm.test.js.snap exports[`<ATOForm /> rendering should render 1 form 1`] = ` <Form className="someForm" > <h4 className="title" > Our Test Subject </h4> <div style={ Object { "marginBottom": "2rem", } } > <ForwardRef(TextInput) disabled={false} helperText="" id="test2" inline={false} invalid={false} invalidText="Invalid error message." labelText="First input field" light={false} onChange={[Function]} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 6 . 11
  • 24. Snapshot Testing //ATOForm.js import { Form, TextInput } from 'carbon-components-react'; import React from 'react'; const ATOForm = () => { return ( <Form className="someForm"> <h4 className="title">Our Test Subject</h4> <div style={{ marginBottom: '2rem' }}> <TextInput id="test2" invalidText="Invalid error message." labelText="First input field" placeholder="Placeholder text" /> </div> </Form> ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // __snapshots__/ATOForm.test.js.snap exports[`<ATOForm /> rendering should render 1 form 1`] = ` <Form className="someForm" > <h4 className="title" > Our Test Subject </h4> <div style={ Object { "marginBottom": "2rem", } } > <ForwardRef(TextInput) disabled={false} helperText="" id="test2" inline={false} invalid={false} invalidText="Invalid error message." labelText="First input field" light={false} onChange={[Function]} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // __snapshots__/ATOForm.test.js.snap exports[`<ATOForm /> rendering should render 1 form 1`] = ` <Form className="someForm" > <h4 className="title" > Our Test Subject </h4> <div style={ Object { "marginBottom": "2rem", } } > <ForwardRef(TextInput) disabled={false} helperText="" id="test2" inline={false} invalid={false} invalidText="Invalid error message." labelText="First input field" light={false} onChange={[Function]} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 6 . 11
  • 25. Snapshot Testing // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 Our Test Subject10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 6 . 12
  • 26. Snapshot Testing // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 Our Test Subject10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 Our Test Subject // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 6 . 12
  • 27. Snapshot Testing Our Test Subject // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 6 . 13
  • 28. Snapshot Testing Our Test Subject // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 // __snapshots__/ATOForm.test.js.snap exports[`<ATOForm /> rendering should render <Form className="someForm" > <h4 className="title" > Our Test Subject </h4> <div style={ Object { "marginBottom": "2rem", } } > <ForwardRef(TextInput) disabled={false} helperText="" id="test2" inline={false} invalid={false} invalidText="Invalid error message." labelText="First input field" light={false} onChange={[Function]} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 6 . 13
  • 29. Snapshot Testing Fail Our Test Subject // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 FAIL src/components/ATOForm/ATOForm.test.js <ATOForm /> rendering ✓ should render 1 form (5ms) ✕ should render a title (5ms) ● <ATOForm /> rendering › should render a title expect(received).toBe(expected) // Object.is equality Expected: true Received: false 19 | it( 'should render a title ', () => { 20 | const wrapper = shallow( <ATOForm /> ); > 21 | expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe | ^ 22 | } ); 23 | } ); at Object.<anonymous> (src/components/ATOForm/ATOForm.test.js:21:73) › 1 snapshot updated. Snapshot Summary › 1 snapshot updated from 1 test suite. Test Suites: 1 failed, 1 total 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 6 . 14
  • 30. Snapshot Testing Fail Our Test Subject // __snapshots__/ATOForm.test.js.snap1 2 exports[`<ATOForm /> rendering should render3 <Form4 className="someForm"5 >6 <h47 className="title"8 >9 10 </h4>11 <div12 style={13 Object {14 "marginBottom": "2rem",15 }16 }17 >18 <ForwardRef(TextInput)19 disabled={false}20 helperText=""21 id="test2"22 inline={false}23 invalid={false}24 invalidText="Invalid error message."25 labelText="First input field"26 light={false}27 onChange={[Function]}28 // __snapshots__/ATOForm.test.js.snap exports[`<ATOForm /> rendering should render <Form className="someForm" > <h4 className="title" > Our Test Subject </h4> <div style={ Object { "marginBottom": "2rem", } } > <ForwardRef(TextInput) disabled={false} helperText="" id="test2" inline={false} invalid={false} invalidText="Invalid error message." labelText="First input field" light={false} onChange={[Function]} 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <h4 className="title">Our Subject</h4> //ATOForm.js1 import { Form, TextInput } from 'carbon-components-react';2 import React from 'react';3 4 const ATOForm = () => {5 return (6 <Form className="someForm">7 8 <div style={{ marginBottom: '2rem' }}>9 <TextInput10 id="test2"11 invalidText="Invalid error message."12 labelText="First input field"13 placeholder="Placeholder text"14 />15 </div>16 </Form>17 18 )19 FAIL src/components/ATOForm/ATOForm.test.js <ATOForm /> rendering ✓ should render 1 form (5ms) ✕ should render a title (5ms) ● <ATOForm /> rendering › should render a title expect(received).toBe(expected) // Object.is equality Expected: true Received: false 19 | it( 'should render a title ', () => { 20 | const wrapper = shallow( <ATOForm /> ); > 21 | expect( wrapper.find( '.title' ).contains('Our Test Subject') ).toBe | ^ 22 | } ); 23 | } ); at Object.<anonymous> (src/components/ATOForm/ATOForm.test.js:21:73) › 1 snapshot updated. Snapshot Summary › 1 snapshot updated from 1 test suite. Test Suites: 1 failed, 1 total 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 6 . 14
  • 31. Coverage reports PASS src/components/Launch/Launch.test.js PASS src/components/ATOForm/ATOForm.test.js ------------|----------|----------|----------|---------- File | % Stmts | % Branch | % Funcs | % Lines ------------|----------|----------|----------|---------- All files | 100 | 0 | 100 | 100 ATOForm.js | 100 | 0 | 100 | 100 ------------|----------|----------|----------|---------- Test Suites: 2 passed, 2 total Tests: 4 passed, 4 total S h t 2 d 2 t t l 1 2 3 4 5 6 7 8 9 10 11 12 6 . 15
  • 33. Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 } )14 } );15 6 . 17
  • 34. Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 } )14 } );15 describe( '<Launch /> interactions', () => { } ) Lauch.js1 2 3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 14 } );15 6 . 17
  • 35. Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 } )14 } );15 describe( '<Launch /> interactions', () => { } ) Lauch.js1 2 3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 14 } );15 it( 'should open Launch Modal when clicked', () => { const wrapper = mount( <Launch /> ); const button = wrapper.find('button'); button.at(0).simulate('click'); } ) Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 6 7 8 9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 14 } );15 6 . 17
  • 36. Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 } )14 } );15 describe( '<Launch /> interactions', () => { } ) Lauch.js1 2 3 4 //Simulate DOM events or a click on the button5 it( 'should open Launch Modal when clicked', () => {6 const wrapper = mount( <Launch /> );7 const button = wrapper.find('button');8 button.at(0).simulate('click');9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 14 } );15 it( 'should open Launch Modal when clicked', () => { const wrapper = mount( <Launch /> ); const button = wrapper.find('button'); button.at(0).simulate('click'); } ) Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 6 7 8 9 10 //After inspecting the code, I can see this is toggled to visible one clicked11 const modalDiv = wrapper.find('div#input-modal');12 expect(modalDiv.hasClass('is-visible')).toBe(true);13 14 } );15 it( 'should open Launch Modal when clicked', () => { const wrapper = mount( <Launch /> ); const button = wrapper.find('button'); button.at(0).simulate('click'); //After inspecting the code, I can see this is toggled to visible one clicked const modalDiv = wrapper.find('div#input-modal'); expect(modalDiv.hasClass('is-visible')).toBe(true); Lauch.js1 2 describe( '<Launch /> interactions', () => {3 4 //Simulate DOM events or a click on the button5 6 7 8 9 10 11 12 13 } )14 } );15 6 . 17
  • 38. “   Keep your code organized with 'describe' and 'it' blocks. -- Sometimes testing can take just as long as writing the component, if not longer. -- Don't be afraid to refactor your code to make the test work. -- Writing tests will help you to gain a broad understanding of your codebase. Also help you to become a better programmer. “   6 . 19
  • 39. Thank you for joining Crushing React Bugs with Jest and Enyme @jannaeesick References:   , , , ,   , ,       Jest Enzyme Carbon Design System How to read Test Coverage report generated using Jest. React function components with Hooks Testing with Jest and Enzyme in React — Part 3 (Best Practices when testing with Jest and Enzyme) Red Hat Marketplace link to this code6 . 20