Plan

Part 5 — State, React Dev Tools, Testing in React

So far so good. We have been building our apps, but all of our component are functional and stateless. Meaning that they can be represented as a function working solely on the props passed to a function and returning the view (which is simple and fantastic), but often we need more. We need to know what the state of input or control is. What data is being chagned by the component and how. While using the jQuery I had this strange, uneasy feeling. Like the spot you couldn’t scratch. It was caused by one simple question. Where does data in my frontend app actually is? Beside the localStorage and stuff like that of course. Like can you look at a control or container and point out: “Yup its data is here and it is…”. It’s very volatile, it’s hard to pinpoint and hard to track the changes. I was really overjoyed when I found that React (and than Flux/Redux) was able to address this concern.

State

We already know what props are. There are like configuration/arguments passed from the smarter and bigger components into the smaller ones. They’re immutable, which is fantastic because most of the issues comes from the uncontrolled mutation of objects. What if we’d like component to have access to property of its own that it is able to read and mutate? Here are stateful components! One example for us to introduce is the TopBar . It has an input and we’d like to use it’s value. We definitely could do that with DOM manipulation. But we won’t. Why? Because the DOM shouldn’t be the source of truth and would actually make it much harder to track the changes in our components and using them. Ok let’s try. First let change component from being a function to a class:

There. Now our component is represented as a class. Now let’s add and use our state:

That’s nice! And still working! But can we do better? Well, yes. I kinda dislike the need to specify the constructor just to initiate the state. We could address this with ES6 class properties and use Babel plugin to do the transformation for us:

Let’s type into terminal:

yarn add --dev babel-plugin-transform-class-properties

This will install the plugin we need. Let’s add entry in our .babelrc file to inform Babel that we’d like to use this transformation:

"plugins": [ "transform-class-properties" ],

What we also need to do is inform the Eslint that we’d like to use Babel parser to take experimental features into consideration:

yarn add eslint@3.x babel-eslint@7 -D

and also update our .eslintrc file with additional entry:

"parser": "babel-eslint",

Now we can change our TopBar.jsx to look like this:

That’s neat. Ok now go to your search input and try to type something.

Yeah, so the value of the input is coming from our state, but we don’t change it value, don’t we? There’s no hook to manipulate state’s value. So we need to add handler to our input and tell it how to manipulate the state. Also we must keep in mind how does the render works. It is being triggered only when one of two will happen:

New props of component were passed to component Components state was mutated

From one side you have to keep your component updated. From the other side you’d like to have as little render cycles as possible. Ok let’s add input handler.

https://gist.github.com/wojciech-bilicki/8a1a772a3a69e49be2ab20d4859c7f67

And here we are approaching one of the greatest React concepts: Unidirectional Data Flow. React makes it really easy to trace what is happening in our components (opposing to two way data binding):

The change in the UIs are caused by only one thing: the render method of given component. And for it to trigger there has to be a call to setState method. That mutates component state, this is basically caused by two things user event (click, input value change) or external data input (ajax call finished, file reading finished). It’s very predictible and deterministic, because component will always look and behave the same with given set of params and state, it like snapshoting. Basically we could represent out component as mathematical function:

UI = f(props, state)

Oh, also you NEVER want to write something like:

this.state.searchTerm = 'test'

Because it won’t trigger the render cycle. React simply wouldn’t care.

Few words about the class properties. Our onInputState function is being automatically bound to the context of this (meaning THIS particular component in this case). Binding is important, because we won’t to mutate state of THIS component. The binding issue would especially be visible while passing function from parent to children, because if we wouldn’t bound it, it could have been called with THIS pointing to children (as the context in which function is being called) instead of parent. I really favor using class properties transform as they provide as little overhead as possible. Yet there are few other ways you could bind function to given component:

Binding in render function:

onChange={() => this.onInputChange()}

Arrow function doesn’t create new context, so THIS in onInputChange function would still point out to our component. Yet you are creating new function on every render cycle, so it can really hurt your performance.

2. You could bind in constructor with

this. onInputChange =this. onInputChange .bind(this);

Putting this in your constructor is totally fine, but in time your constructor can bloat unnecessary because of this technique as you add more functions to your component.

3. There’s also create-react-class package, that can handle autobinding.

ReactDevTools

Ok, so how do we actually use our search to filter our heroes that we display. It would be extremely easy with Redux, but you don’t always need Redux. To be honest you should really think through bringing Redux to your project because it definitely adds more work as being really powerful tool. As the creator of Redux said you might not need Redux.

To help us with that task we can use ReactDevTools. I believe that everyone is familiar with using Developer Tools for browsers, but in case of React we want more. Standard inspector shows us what is actually being rendered to the DOM, but is omitting very important stuff like React components, props and state. We can use React Developer Tools to shine some light on that. Go to Chrome Browser and install React Developers Tools add-on. Than after opening the Developer Tools, you will see another tab named ‘React’.

React Dev Tools

As you can see it is showing us the whole tree hierarchy as well as the props and state of component. This is priceless while debugging. You can also modify the state of component on the fly. How? In React Developer Tools click on TopBar component. Than go to your console tab and type:

$r.setState({searchTerm: 'A'})

The $r symbol references selected React component, just like $0 references the DOM node if one is being selected in inspector tab. Pretty sweet. Ok let’s modify our TopBar so that we could actually filter our heroes:

We are importing Link component from react-router-dom . We used it before but this time we specify the to value as being dynamically infered using the state of our component. Now we can change our App.jsx :

As you can see we added another Route pointing to Master component but this time it’s different (maybe there’s a way to add this in our previous Route but I couldn’t yet figure out how, please leave a comment if you know how to approach this) as we are specifying another path with parameter that we’d like to use in our component. We can tell React Router that part of path should be dynamic and accessible by adding colon before it. If route will match with our path, we’ll find our value inside props.match.params.{nameOfParam} . Now we can type something is input, press search and use the React Developer Tools to confirm that the searchTerm param is actually being passed to our Master component.

Ok now let’s change our Master component to actually do the filtering:

Now it’s all great, but what happens if we don’t type anything to our search input and press the button anyway? Well, we get an empty view. Not really what we’d desire. Easy fix. We need to tell router that the searchTerm is optional param in our route by adding question mark:

path="/search/:searchTerm?

Neat!

Jest Component Testing

Someone much wiser than me once said: “All code is guilty until proven else”. I couldn’t agree more. Yet, how often do we test it? I never was able to really stick to the TDD regime, but I was trying to stick with it in few of me projects outside of work and it definitely proved itself as interesting approach. I was initially thinking about leaving this part of React workshop out of scope, but I believe that it is to important to simply cut it out.

When it comes to choosing how to test, what tools to choose and what to test there are many opinions. I used Jasmine about 1,5 year ago and it was quite alright, but I’ve heard that Mocha & Chai was also doing its job well. It was a time when Jest was slow and sloppy and I couldn’t really care less for it. Than Jest was actually rewritten from the ground up, to become my first choice when it comes to test React as for now. To add to it there’s this fantastic piece of work from folks over in AirBnB called Enzyme. Its job is to easily let you travers the React components tree with very pleasing interface (kinda sorta jQuery like). Together Enzyme & Jest keep you fully covered when it comes to React & Redux testing.

Ok so let’s add those to our project:

yarn add --dev jest enzyme

Jest will go through your project searching for 3 types of files:

Ones held in every folder called __tests__ Every each and single file with *.test.js extension Every each and single file with *.spec.js extension

This gives you wide opportunity on where to place your tests. For ones keeping them all in __tests__ folder seems like good idea. Others would like to keep them next to the files that are being tested. It’s really up to personal preference.

Also Jest comes with this fantastic idea of snapshot testing. The component is being serialized to a simple object representation and written into a file. Than if in any time in future component structure is being changed we are warned about that change as component serialization isn’t matching the previous one. At the begining I thought that this kind of testing is useless and doesn’t bring any value. Oh boy, was I wrong! If you add simple input integration from Enzyme to snapshots, you’re on your way to have really good testing coverage in your project.

Ok let’s try and snapshot our component in our __test__ folder:

Yeah, I believe that our linter can be rather upset with what we’re doing right now. Let’s ease it wit new configuration entry. Add to env in .eslintrc :

"jest": true

add also add script in package.json to run the tests:

"test": "jest"

Aaaand we fail. At the very beginning. How wonderful. Apparently we can’t use import statement while writting our tests. Seems like Jest isn’t really aware that we are using ES6 syntax. Well, let’s tell him about it in .babelrc

Great! Let’s run this one again! Annnnd we fail:

Ok great. Jest doesn’t really know how to work against webpack. Remember that webpack is bundling images/js/jsx/css. Jest concerns itself only with tests and doesn’t really know how to work against all those files. Let’s give him a hand. Go to our package.json and add an entry:

also in root directory add __mocks__/fileMock.js with contents as:

module.exports = 'test-file-stub';

Great!!!! Now it’s definitely working!

Or not.

Ok so here comes funny part about testing. Mocks. You see… jest mocks. You get it?

It seems that we need to mock out our Link component. What we won’t is its simple serializable representation instead of all the actual Link functionality, because that not what we are testing here. How to mock it out? It’s easy (hahaha NO. I’ve spent some time searching for how to do mocking first time I needed it), simply change you TopBar.spec.jsx file content to:

Now let’s run it. Greeeeeen. Finaaaallly. Ok as you can see in __test__ folder there’s new one called snapshots . And there you can view your TopBar.jsx serialization. Nothing fancy, but it is definitely enough to maintain our components integrity.

So what exactly is snapshot testing all about? Let’s go to our TopBar.jsx and update it. Change the Super Hero Team to Super Marvel Team . As you can see the test will fail because the rendered component doesn’t match the previous snapshot. How to react (hahahahaha… it’s time to stop) to that?

Well, the change is side effect of some code manipulation that definitely shouldn’t be there. Than we should definitely investigate the cause of this change and determine whether it is a bug sneaking upon us and fix our codebase. Seems like a reasonable thing to do. Ok but what if the change in the component was introduced on purpose? For example we had to add a label or image to component and we’d like this new component to be snapshoted, treated as correct and matched against in our future test runs?

Simple. Go to our package.json and add a script:

"updateSnapshots":"NODE_ENV=test jest --u"

and than naturally run yarn updateSnapshots . The --u flag tells Jest to build new set of snapshots based upon current looks of component.

Result of updating the snapshots

Ok lets try with another snapshot test. How about our Master.jsx ? Seems easy:

Ok let’s know change anything in our HeroCard component. Like h4 to h5 . Not good. We were testing the Master component, we change HeroCard component and now the Master test is failing? It seems like Master.spec.jsx is testing too much and knows too much about the HeroCard internal structure. Yeah, that’s because react-test-renderer is doing deep render. Meaning it will not only serialize the given component but also it’s children right to the HTML5 tags. We’d like to have something simpler, more independent and more shallow. Thankfully the fantastic Enzyme can help us with that one! But to make it work we must actually use enzyme serializer instead of the one that Jest is providing by default. Go to your package.json and add another entry to the jest object:

"snapshotSerializers": ["jest-serializer-enzyme"]

Now go back to your Master.spec.jsx and change it to use the shallow renderer from enzyme:

Of course we must update the snapshots now as we are using different renderer. You’re more than welcome to see what was actually changed after running yarn updateSnapshots . Now we can manipulate HeroCard.jsx and see that it have no impact on Master.spec.jsx . Great! Exactly what we need!

Enzyme has additional features that let’s you test component in depth. What actually should you be testing then? Well, maybe not if the given div has a proper attributes or if the background color is correct, but definitely stuff like integration between components, user input events or (later in this course) Redux part of your app. For example we should check if the HeroCard components are actually being rendered if the correct props are passed to Master . Let’s add another test:

That’s rather nice. We can use Enzyme to find components inside another component and check whether the amount is correct. The issue is that the line 9 and 14 are repeating. Yet we’d like to have fresh copy of master constant to maintain our test independence. We could change the test syntax a little to address this. Writing them using test function is fine, but we could use the describe/it syntax, to run some code before each of our tests as well as move into more BDD area:

Now we create new master variable before each test and we moved it to the upper scope so that every test has an access to it. Ok as for now I’d like to write one more test. One checking if the state is actually being modified inside TopBar if we type into input. Let’s change the TopBar.spec.jsx to use shallow and describe/it syntax.

Ok we again seeing the use of the find method which doesn’t only take other component but can also take standard css selectors to find elements. There’s also fantastic possibility to simulate the change event, but to make it work we must pass the object that mocks the actual event object that we use to modify the state. To check agains the components state we use state function to which we pass the key in the state that we are interested in.

Great! To be honest you don’t need much of test when it comes to React, you can definitely rely on Snapshot testing and strong typing in JS. Sprinkle few enzyme test here and there to ensure that your components are behaving how they suppose to:

Of course things are different with Redux.

Ok that pretty much sums up the testing except for one thing really. Often we’d like to know what is tested and what parts of the app aren’t covered with tests at all. There’s this fantastic tool called istanbul to help us with that. Let’s add it to our project:

yarn add --dev instanbul

and add a script for it to run:

"testCoverage": "NODE_ENV=test jest --coverage"

and run it (You kno how ;)).

Ok what we can see is that our tests are running and we get report in our terminal about the coverage. Pretty good I must say. We can also see what lines of code weren’t invoked by our test:

Test coverage

As well as the new coverage folder created automatically in our project. In lcov-folder we can find the raport in form of html which is easy to show in our continous integration environment! Fantastic!

Oh also! You can add in your package.json :

"testWatch": "NODE_ENV=test jest --watch"

To run tests automatically if any of associated file will be modified to watch continuously for failing tests!

I’ll see you in next part where we will discuss Hot Reloadin and (finally!) strong types in JavaScript! Cheers!