React to Changes with Pure Components
Here we are again, and as promised in my last story, I’ll be sharing my experience on how to apply Unit Tests and TDD on a React application. Follow along, as this tale shall not be forgotten.
Winds of Change…
This is a story about changing times and modernisation, in a land of ashes, fire, war… and addiction for online shopping.
Our tale begins with our Dark Wizard, Zaurom, whose business of dark weaponry has been on decline due the lack of blacksmithing shops on Nordor. Orcs have become very lazy these days and they prefer to do online shopping so they can customise their armour and weapons for battle and have them delivered at their door.
Master Zaurom summons his most loyal and expert programmer-wizard, and threatens … I mean asks him to build an online shop for custom warcraft artifacts. The first orders are:
- Include a catalog with thumbs or the war artifacts (Swords, Shields, Machinery, Spells, Supplies) also showing price in gold, name ,and short description.
- Show the total amount of the purchase in a small widget next to the catalog of artifacts.
- Artifacts can be added to the shopping cart by clicking on the image or the name of the item in the catalog.
This should be fairly easy tasks — says the dark ruler. An so like that , the wizard returns to his chamber in the black tower to begin with his task.
As an expert and wise sorcerer he already had prepared a starter project (Clone it to keep following)that leveraged him from the boring initial set up.
First thing first. As an expert developer er… sorcerer, he knows the value and importance of Unit Tests, TDD, and the simplicity of Tape, so he starts his code this way:
The intention of this unit test is to make sure the catalog renders the right markup from the data model provided.
For that we are using a set of magic tools (React, cheerio, React-Dom ) and a technique called Pure Components to facilitate our check up task.
The wizard reviews his old books to remember why he should follow this path…
“Purity and Simplicity are the secret for true testability, reliability and scalability. Like the ingredients for the Philosopher’s Stone, only pure components can create such magical master piece. ”
Pure Components are a way of building React applications by making every re-usable component a factory function that returns a React Element based on the properties(props) passed to it.
The benefits from this style are significant! — says the sorcerer to himself. Not worrying about context really simplifies testing and also makes the composition task a charm.
Now to finish the tasks commended by his master, the sorcerer thinks that it could be a good idea to make the product display logic also component. So he writes the test for that:
If you are wondering how on the middle earth are we using JQuery here, then I’ll disappoint you, we are not, we use cheerio.
Cheerio is a simplified version of the JQuery API for the server side, which really helps to get testing done without the headache of dealing with full DOM stubbing. Thanks to Eric Elliott for the sample of using cheerio for these scenarios.
Remember, pure components are context free and don’t care where they are rendered, this approach should work as long as you respect components purity — says the sorcerer inner voice.
Mixing it up…
The tests don’t lie:
✓ Catalog should be a list of 3 .product items
✓ Product should have image, name, description and price displayed
# tests 5
# pass 5
Composing was easy. Pure Functional Components have proven to be worthy.
Then, the deep roaring voice of his master sounded like a thunder in the sorcerers chamber — Show me what you’ve got. — said the dark master.
The sorcerer moved fast to wire the application with some fake data and show his master what he has achieved so far…
And and the index.js entry…
With that he was able to show an overview of the weapons catalog and save his soul… for now.
Firing things up
So far the magic created is cool, but it does not please the Dark Lord. It is time for our wizard to spice things up and handle actions in the cart.
And of course here is a test for that…
Purity and simplicity first. The Component is not responsible for adding the selected item to the shopping cart. Its task is to show a visualisation of the abstract data and provide the user with a way to interact with the system.
The a small refactor to the product component:
To be continued…
How would this story end? Stay tuned and you’ll find out on the continuation of this article where I wire this up with Functional Reactive Programming.
The Take off
I think that Pure Components on React area great addition to this O.14 version. As you see, they have several benefits like:
- Testability. Being stateless component functions makes testing a charm. No DOM context or instance state to be worried. Just pass a model an you are ready to test.
- Reliability. No magic globals or inherited mess. Every dependency required from the component is injected or its origin is seen.
- Scalability. Functions are the simplest expression of a computer program. Pure Component Functions can easily be composed to create more complex solutions and you would still be able to swap blocks and extend with a lot more confidence.
- Swap. This way of handling components facilitates switching from view libraries. If you don’t want to use React anymore, you can change it by any virtual-dom library (Deku, Hyperscript) that supports JSX. You don’t tie your app to React.
Remember Unit Testing is about verifying functionality of individual units of code. Im saying this because I have witnesed, over and over again, developers pull their hair off and drop the practice because they try to test stuff that shouldn’t be part of unit test, waisting precious time. Im talking of stuff like simulating clicks, DOM events, server events, full libraries, and so on.
Full integration tests or E2E should be delegated to a different layer of tools like NightWatch, PhantomCSS (UI regression). Ask your code the essential questions and focus on deliver functionality.
Thanks for reading this far. See you next time.