Mastering React Test-Driven Development - Daniel Irvine - E-Book

Mastering React Test-Driven Development E-Book

Daniel Irvine

0,0
49,25 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.
Mehr erfahren.
Beschreibung

Implement TDD for your React applications using Jest, React Router, Redux, and GraphQL/Relay. Learn BDD and end-to-end acceptance testing with CucumberJS and Puppeteer.

Key Features



  • Learn the TDD process using the React framework
  • Build complex, real-world applications with a pragmatic approach to TDD
  • Use Cucumber for acceptance and BDD testing, bringing TDD to the wider team

Book Description



Many programmers are aware of TDD but struggle to apply it beyond basic examples. This book teaches how to build complex, real-world applications using Test-Driven Development (TDD). It takes a first principles approach to the TDD process using plain Jest and includes test-driving the integration of libraries including React Router, Redux, and Relay (GraphQL).

Readers will practice systematic refactoring while building out their own test framework, gaining a deep understanding of TDD tools and techniques. They will learn how to test-drive features such as client- and server-side form validation, data filtering and searching, navigation and user workflow, undo/redo, animation, LocalStorage access, WebSocket communication, and querying GraphQL endpoints.

The book covers refactoring codebases to use the React Router and Redux libraries. via TDD. Redux is explored in depth, with reducers, middleware, sagas, and connected React components. The book also covers acceptance testing using Cucumber and Puppeteer.

The book is fully up to date with React 16.9 and has in-depth coverage of hooks and the 'act' test helper.

What you will learn



  • Build test-driven applications using React 16.9+ and Jest
  • Build complete web applications using a variety of HTML input elements
  • Understand the different types of test double and when to apply them
  • Test-drive the Integration of libraries such as React Router, Redux, and Relay (GraphQL)
  • Learn when to be pragmatic and how to apply TDD shortcuts
  • Test-drive interaction with browser APIs including fetch and WebSocket
  • Use Cucumber.js and Puppeteer to build BDD-style acceptance tests for your applications
  • Build and test async Redux code using redux-saga and expect-redux

Who this book is for



The target audience for this book is JavaScript developers who are looking to implement test-driven and behavior-driven approaches for their React applications.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB

Seitenzahl: 511

Veröffentlichungsjahr: 2019

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Mastering React Test-Driven Development

 

 

 

 

 

 

 

Build rock-solid, well-tested web apps with React, Redux and GraphQL

 

 

 

 

 

 

 

 

Daniel Irvine

 

 

 

 

 

 

 

 

BIRMINGHAM - MUMBAI

Mastering React Test-Driven Development

Copyright © 2019 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

 

Commissioning Editor: Amarabha BanerjeeAcquisition Editor:Trusha ShriyanContent Development Editor:Keagan CarneiroTechnical Editor: Sachin SunilkumarCopy Editor: Safis EditingProject Coordinator:Kinjal BariProofreader: Safis EditingIndexer:Rekha NairGraphics:Alishon MendonsaProduction Coordinator:Jayalaxmi Raja

First published: May 2019

Production reference: 1020519

Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.

ISBN 978-1-78913-341-7

www.packtpub.com

To Nige, my first mentor, who taught me the importance of slowing down.
– Daniel Irvine
 
mapt.io

Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.

Why subscribe?

Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals

Improve your learning with Skill Plans built especially for you

Get a free eBook or video every month

Mapt is fully searchable

Copy and paste, print, and bookmark content

Packt.com

Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.

At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks. 

Contributors

About the author

Daniel Irvine is a software consultant based in London. He is a member of the European software craft community and works with a variety of languages including C#, Clojure, JavaScript, and Ruby. He’s a mentor and coach for junior developers and runs TDD and XP workshops and courses. When he’s not working, he spends time cooking and practicing yoga. He co-founded and runs the Queer Code London meetup.

This book would not be what it is without the input of my technical reviewer, Raimo Radczewski, who is also the author of the expect-redux package that is used in this book. I met Raimo a few years ago through the European software craft community. We bonded at a SoCraTes conference and found that we shared many of the same driving forces. Through many conversations, I learned to respect his thoughtfulness, kindness, and, of course, his deep knowledge of JavaScript and the React ecosystem. So, when I first took on this project, I immediately asked Raimo to come on board. Thankfully, he said yes. In the following eight months, he had a difficult job of reading though many drafts of—shall we say—variable quality. Those who have worked with me know that I can be lazy, careless, brazen, and inconsistent. Well, Raimo has seen it all and more, so firstly, I must thank him for continuing with the project in spite of the early drafts. I must also thank him for teaching me about many of JavaScript’s nuances, of which I simply wasn’t aware. He also guided me back toward idiomatic React code, because until I wrote this book I had really been writing JavaScript “out in the wilderness,” with my own style. He brought me back in from the cold. He suggested some simplifications to my implementations; for example, the undo/redo reducer in Section 3, which would have been a great deal more complicated without his critical eye. I blamed my terrible code on burn-out, but actually, Raimo is a fantastic programmer and I look forward to the next occasion that we get to work together. My editor, Keagan Carneiro, has been constantly positive and supportive, not once ever judging me for missing my self-imposed deadlines, which toward the end I missed consistently. We got through it in the end. Of all the wonderful things he did for me, perhaps the most powerful was the push to embrace hooks. When I first informed him in November 2018 that the React team had announced this weird thing called hooks that looked horrendous and that I couldn’t ever imagine taking off, but that we might have to consider doing a chapter on, he turned around and suggested that I rewrite the entire text entirely to use hooks. Bearing in mind we were halfway through at this point, it was a pretty big ask. Of course, I knew he was right and I trusted his assessment, so I had to go through the five stages of grief of denial, anger, bargaining, depression, and acceptance in super-quick time, before getting on with it. (I believe Raimo is still hovering somewhere around the bargaining stage.) In the end, we were only delayed by a month, so I have to thank Keagan for ensuring that the book wasn’t out of date before it was even published.Sachin Sunilkumar, my technical editor, was wonderfully patient with me as I was reworking code snippets right until the last moment. He went on a journey of discovery with me as we built and tested against alpha releases of React. That was fun and stressful in equal amounts! There are a number of other friends who stepped in at the last moment to review content when I was rushing with the final draft. Their assistance was invaluable. The text is much better for their efforts. Charlotte Payne, Dan Pelensky, Isidro López, Makis Otman, Sam Szreter, Zach Shaw: thank you. I hope you enjoy seeing your suggested improvements in print. To the development team at Idean—in particular, Brendan Murphy, Lucy Monie Hall, and Zach Shaw—thank you for listening to me bang on about “my book” at least once a week. I cannot finish without thanking my partner, Phillipe, who has suffered as I embarked on this project, my first book. Staying on track while still having a day job was a mammoth effort for me. It really took it out of me. Phillipe put up with me as I was tired, distracted, creatively drained, emotionally distraught, unavailable, and—toward the end—burned out, monosyllabic, and not much fun. He supported me through the project from start to finish. Thank you.

About the reviewer

Raimo Radczewski is an IT consultant from Berlin, Germany. His journey through the world of software engineering has taught him not just quite a few languages and paradigms, but also how to build and lead engineering teams. He's an advocate for test-driven development and maintains testing tools for the React ecosystem. He organizes SoCraTes Day Berlin and the Global Day Of Coderetreat, two grassroots communities for IT workers who are curious about software crafting and eXtreme Programming. His current focus is founding a tech cooperative to support clients in building a professional and mindful engineering culture. He tweets under @rradczewski.

Thank you, Daniel, for giving me the opportunity to help create this most excellent introduction to TDD in React. It will surely land on the bookshelves of many of my clients. Thank you, Andreas and Jan, for being the first people to show me Test-Driven-Development and for introducing me to the communities that I continue to learn so much from.

 

 

 

Packt is searching for authors like you

If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.

Table of Contents

Title Page

Copyright and Credits

Mastering React Test-Driven Development

Dedication

About Packt

Why subscribe?

Packt.com

Contributors

About the author

About the reviewer

Packt is searching for authors like you

Preface

Who this book is for

What this book covers

To get the most out of this book

Keeping up with the book's Git history

Getting started before Chapter 1

Working with section tags

Solving the exercises

Debugging when things go wrong

Download the example code files

Conventions used

Understanding code snippets

JavaScript syntax

Prettier

Arrow functions

Object and array destructuring

Directory structure

Get in touch

Reviews

Section 1: First Principles of TDD

First Steps with Test-Driven Development

Technical requirements

Creating a new React project from scratch

Installing NPM

Creating a new Jest project

Commit early and often

Bringing in React and Babel

Displaying data with your first test

Writing a failing test

Writing your first expectation

Rendering React from a test

Make it pass

Backtracking on ourselves

Refactoring your work

Promoting variables

Using a beforeEach block

Extracting methods

Writing great tests

Red, green, refactor

Streamlining your testing process

Rendering lists and detail views

Rendering the list of appointments

Specifying list items

Selecting data to view

Initial selection of data

Adding events to a functional component

Manually testing our changes

Adding an entrypoint

Putting it all together with Webpack

Before you check in...

Summary

Exercises

Further learning

Test-driving Data Input with React

Extracting a test helper

Adding a form element

Extracting a form-finder method

Accepting text input

Extracting an expectation group function

Passing in an existing value

Extracting out a field-finder function

Labeling the field

Checking for null or not

Saving the customer information

Submitting a form with data

Using state instead of props

Duplicating fields

Nesting describe blocks

Generating parameterized tests

Solving a batch of tests

Modifying handleChange to work with multiple fields

Finishing off the form with a submit button

Selecting from a dropdown

Providing options to a dropdown

Utilizing defaultProps to specify real data

Pre-selecting a value

Completing the remaining tests for the select box

Making a choice from radio buttons

Constructing a calendar view

Displaying radio buttons for available appointments

Hiding input controls

Finishing it off

Manually testing your solution

Summary

Exercises

Further learning

Exploring Test Doubles

What is a test double?

Learning to avoid fakes

Submitting forms using spies

Untangling Arrange-Act-Assert

Watching it fail

Making spies reusable

Using a Jest matcher to simplify expectations

Stubbing the fetch API

Replacing global variables with spies

Installing the window.fetch polyfill

Acting on return values with stubs

Acting on the fetch response

Displaying errors to the user

Extracting test helpers

Using Jest to spy and stub

Extracting spy helpers

Using jest.spyOn to spy on module mocks

Drying up DOM queries

Extracting container.querySelectorAll

Drying up DOM events

Summary

Exercises

Further learning

Creating a User Interface

Fetching data on load with useEffect

Stubbing exported constants

Using props within useEffect

Passing customer data through to AppointmentForm

Passing through props to the child component

Working with the shallow renderer

Understanding the importance of spiking

Building shallow renderer helpers

Listing element children

Encapsulating render output to dry up tests

Building a new root component

Summary

Further learning

Section 2: Building a Single-Page Application

Humanizing Forms

Performing client-side validation

Submitting the form

Extracting non-React functionality into a new module

Handling server errors

Indicating that the form has been submitted

Refactoring long methods

Summary

Exercises

Further learning

Filtering and Searching Data

Displaying tabular data fetched from an endpoint

Paging through a large data set

Adding a next page button

Adding a previous page button

Filtering data

Refactoring to simplify component design

Adding table row actions

Specifying the render prop in App

Summary

Exercises

Test-driving React Router

General rules for test-driving React Router

Using shallow rendering for the simplest results

Passing React Router props down through your components

Avoiding withRouter

Building a root component

Using the Router Switch component

Testing the default route

Invoking render functions and inspecting their properties

Changing location using history.push

Using the location query string to store component state

Replacing onClick handlers with Link components

Using a parent component to convert a query string to props

Replacing onChange handlers with history.push

Summary

Exercises

Further learning

Test-driving Redux

Prerequisites

Test-driving a Redux saga

Designing the state object

Scaffolding the saga and reducer

Scaffolding a reducer

Setting up an entrypoint

Making asynchronous requests with sagas

Completing the reducer

Pulling out generator functions for reducer actions

Switching out component state for Redux state

Building a helper function to render with store

Submitting a React form by dispatching a Redux action

Protecting against silent breakages

Shifting workflow to Redux

Stubbing out components built with useMemo

Navigating router history in a Redux saga

Separating Redux connection from presentation

Summary

Exercises

Further learning

Test-driving GraphQL

Installing Relay

Testing the Relay environment

Building the GraphQL reducer

Building the CustomerHistory component

Tying it together in App

Compiling Relay queries

Summary

Exercises

Further learning

Section 3: Interactivity

Building a Logo Interpreter

Studying the Spec Logo user interface

Looking through the codebase

Undoing and redoing user actions in Redux

Building the reducer

Setting the initial state

Handling the undo action

Handling the redo action

Attaching the new reducer

Building buttons

Saving to LocalStorage via Redux middleware

Building middleware

Changing keyboard focus

Writing the reducer

Adding the reducer to the store

Focusing the prompt

Requesting focus in other components

Summary

Further learning

Adding Animation

Isolating components for animation

Designing the component

Extracting out StaticLines

Building an AnimatedLine component

Animating with requestAnimationFrame

Drawing lines

Cleaning up after useEffect

Rotating the turtle

Summary

Exercises

Working with WebSockets

Designing a WebSocket interaction

The new UI elements

Splitting apart the saga

Test-driving a WebSocket connection

Streaming events with redux-saga

Updating the app

Summary

Exercises

Further learning

Section 4: Acceptance Testing with BDD

Writing Your First Acceptance Test

Integrating Cucumber and Puppeteer into your code base

Writing your first Cucumber test

Using data tables to perform setup

Summary

Adding Features Guided by Acceptance Tests

Adding acceptance tests for a dialog box

Fixing acceptance tests by test-driving production code

Adding a dialog box

Updating sagas to reset or replay state

Adding better wait support

Alerting when the animation is complete

Updating step definitions to use waitForSelector

Exercises

Summary

Understanding TDD in the Wider Testing Landscape

Test-driven development as a testing technique

Best practices for your unit tests

Improving your technique

Manual testing

Demonstrating software

Testing the whole product

Exploratory testing

Debugging in the browser

Automated testing

Integration tests

Acceptance tests

Property-based and generative testing

Snapshot testing

Canary testing

Not testing at all

When quality doesn't matter

Spiking and deleting code

Summary

Further learning

Other Books You May Enjoy

Leave a review - let other readers know what you think

Preface

This is a book about dogma. My dogma. It is a set of principles, practices, and rituals that I have found to be extremely beneficial when building React applications. I try to apply these ideas in my daily work, and I believe in them so much that I take every opportunity to teach others about them. That's why I've written this book: to show you the ideas that have helped me be successful in my own career.

As with any dogma, you are free to make your own mind up about it. There are people who will dislike everything about this book. There are those who will love everything about this book. Yet more people will absorb some things and forget others. All of these are fine. The only thing I ask is that you maintain an open mind while you follow along, and prepare to have your own dogmas challenged.

Test-driven development (TDD) did not originate in the JavaScript community. However, it is perfectly possible to test-drive JavaScript code. And although TDD is not common in the React community, there's no reason why it shouldn't be. In fact, React as a UI platform is a much better fit for TDD than older UI platforms, due to its elegant model of functional components and state.

So what is TDD, and why should you use it? Test-driven development is a process for writing software that involves writing tests, or specifications, before writing any code. Its practitioners follow it because they believe that it helps them build and design higher-quality software with longer life spans, at a lower cost. They believe it offers a mechanism for communicating about design and specification that also doubles up as a rock-solid regression suite. There isn't much empirical data available that proves any of that to be true, so the best you can do is try it out yourself and make your own mind up.

Perhaps most importantly for me, I find that TDD removes the fear of making changes to my software, and that this makes my working days much less stressful than they used to be. I don't worry about introducing bugs or regressions into my work, because the tests protect me from that.

TDD is often taught with 'toy' examples: todo lists, temperature converters, Tic Tac Toe, and so on. This book teaches two real-world applications. Often, the tests get hairy. We will hit many challenging scenarios and come up with solutions for all of them. There are over 450 tests contained within this book, and every one will teach you something.

So, before we begin, a few words of advice.

This is a book about first principles. I believe that learning TDD is about understanding the process in exceptional detail. For that reason, we do not use Enzyme or react-testing-library. Instead, we build our own test helpers. Doing so is not very complicated. The benefit of doing so is a deeper understanding and awareness of what those testing libraries are doing for you. I am not suggesting that you shouldn't use these tools in your daily work—I use them myself—but I am suggesting that going without them is a worthwhile adventure.

This book uses React hooks. These are a new feature in version 16.8, and we also make use of the act function, which became usable in version 16.9. There are no class components in this book. I believe that we should embrace hooks because functional components using hooks are simpler than class components. I embraced hooks during the process of writing this book, which originally started out as a book with class components. Halfway through, we decided to scrap classes entirely and instead, focus on the future.

On that topic, the JavaScript and React landscape changes at such a pace that I can't claim that this book will remain 'current' for very long. That is another reason why I use a first-principles approach. My hope is that when things do change, you'll still be able to use this book and apply what you've learned to those new scenarios.

There are a variety of themes that run throughout the book. The theme of first principles is one I've already mentioned. Another is systematic refactoring, which can come across as rather laborious, but is a cornerstone of TDD and other good design practices. I have provided many examples of that within these pages, but for brevity, I sometimes jump straight to a 'post-refactored' solution. For example, I often choose to extract methods before they are written, whereas in the real world, I would usually write methods inline and only extract when the containing method (or test) becomes too long.

Yet another theme is that of cheating, which you won't find mentioned in many TDD books. It's an acknowledgment that TDD is really a scaffold around which you can build your own rules. Once you've learned and practiced the strict version of TDD for a while, you can learn what cheats you can use to cut corners. What tests won't provide much value in the long run? How can you speed up repetitive tests? So, a cheat is almost like saying you cut a corner in a way that wouldn't be obvious to an observer if they came to look at your code tomorrow. Maybe, for example, you implement three tests at once, rather than one at a time.

Finally, do not for a second think that I wrote this book in a linear sequence from start to finish, or that I knew exactly what order to write the tests. It took a great deal of spiking, trial and error, and making horrendous mistakes before I ended up with the text you have before you. Needless to say, I am now an expert with git rebase.

Who this book is for

If you're a React programmer, this book is for you. I aim to show you how TDD can improve your work.

If you're already knowledgeable with TDD, I hope there's still a lot you can learn from comparing your own process with mine.

If you don't know already know React, you will benefit from spending some time running through the Getting Started guide on the React website. That being said, TDD is a wonderful platform for explaining new technologies, and it's entirely plausible that you'll be able to pick up React simply by following this book.

This book covers in-depth usage of React hooks, which are very new at the time of writing. If you're a React developer and hoping to learn how to use React without classes, then you will indeed learn that by reading this book.

What this book covers

Chapter 1, First Steps with Test-Driven Development, introduces Jest and the test-driven development cycle. We use them to build a rendering of customer information on a page.

Chapter 2, Test-driving Data Input with React, covers using React component state to manage the display and saving of forms.

Chapter 3, Exploring Test Doubles, introduces various types of test double that are necessary for testing collaborating objects. The collaborator we use in this chapter is the browser fetch API to send and receive data from our application backend.

Chapter 4, Creating a User Interface, ties everything with a root component that threads together a user journey.

Chapter 5, Humanizing Forms, continues with form building by looking at dealing with client- and server-side validation errors, and adding an indicator to show that data is being submitted.

Chapter 6, Filtering and Searching Data, shows building a search component with some complex interaction requirements, in addition to complex fetch request requirements.

Chapter 7, Test-driving React Router, introduces the React Router library to simplify navigation with our user journeys.

Chapter 8, Test-driving Redux, introduces Redux into our application in an effort to simplify our components and evolve our application architecture into something that will support larger use cases.

Chapter 9, Test-driving GraphQL, introduces the GraphQL library to communicate with a GraphQL endpoint that's provided by our application backend.

Chapter 10, Building a Logo Interpreter, introduces a fun application that we begin to explore by building out features across both React components and Redux middleware: undo/redo, persisting state across browser sessions with LocalStorage API, and programmatically managing field focus.

Chapter 11, Adding Animation, covers adding animations to our application using the browser requestAnimationFrame API, all with a test-driven approach.

Chapter 12, Working with WebSockets, adds support for WebSocket communication with our application backend.

Chapter 13, Writing Your First Acceptance Test, introduces CucumberJS and Puppeteer, which we use to build acceptance tests for existing functionality.

Chapter 14, Adding Features Guided by Acceptance Tests, integrates acceptance testing into our development process by first building acceptance tests, before dropping down to unit tests.

Chapter 15, Understanding TDD in the Wider Testing Landscape, finishes the book by looking at how what we've learned fits in with other test and quality practices, and provides some suggestions about where to go from here.

To get the most out of this book

There are two ways to read this book.

The first is to use it as a reference when you are faced with specific testing challenges. Use the index to find what you're after and move to that page.

The second, and the one I'd recommend starting with, is to follow the walk-throughs step by step, building your own code base as you go along. In this section, I'll detail how to do that.

You will need to be at least a little proficient with Git: a basic understanding of the branch, checkout, clone, commit, diff, and merge commands should be sufficient.

Keeping up with the book's Git history

This section details all you need to know to work effectively with Git while you're following along with the walk-throughs.

This book is up-to-date with the latest version of React (16.9.0-alpha.0). Packt will update the code repository for future release cycle of React 16.9. Please note this version is not yet production ready. A production release of 16.9 is due for release soon. 

Getting started before Chapter 1

The book has an accompanying GitHub repository that contains all of the walk-throughs already implemented in a series of commits. You should clone this to your local development machine as you'll be working within it.

If you have a GitHub account, I suggest you fork the repo so that you can push your work to keep a copy safe. Use the

Fork

button in the top-right hand corner of the GitHub page to do this. The repository is located at 

https://github.com/PacktPublishing/Mastering-React-Test-Driven-Development

.

Once forked, you can then clone this locally by going to a terminal window and typing the following command, replacing

<username>

with your GitHub username:

git clone [email protected]:<username>/Mastering-React-Test-Driven-Development.git

You may wish to rename the directory to something shorter. On my machine, I've used the name 

react-tdd

.

Change into this directory using the 

cd

 command.

Issue the command

git checkout tags/starting-point

.

Finally, issue the command

git checkout -b starting-point-mine

to create your own branch from this point.

You're now ready to begin Chapter 1. If the last two commands didn't make any sense, don't panic: I'll explain about tags and branches now.

Working with section tags

There are two separate code bases in this book, and they have their own branches: appointments and spec-logo. Chapter 1 to Chapter 9 cover appointments; Chapter 10 to Chapter 14 cover spec-logo. (Chapter 15 doesn't have any code.)

If you were to check out these branches, you'd get the final, completed versions of the code. This is an interesting sneak peak but it's not how you'll get started.

Instead, many sections have a designated tag, so you can skip to the tag and examine the code at that point. If you see a callout like this:

The Git tag for this section is animation.

...then you can skip to this tag by issuing the following command:

git checkout tags/animation

Once you've output that command, you will be in the detached head state. If you want to begin making changes at that point, you should create a new branch from the tag and work on that. I'd suggest suffixing the name with -mine so that your branches are clearly distinguishable from tags:

git checkout -b animation-mine

You can then commit to this branch. If you have been following along judiciously within your own branch, then you do not need to check out each tag, since you'll already have all of the same code.

However, sometimes you will see a callout like the one that follows, and that means you will need to check out the new tag:

The Git tag for this section is load-available-time-slots.It contains solutions to the exercises from the previous chapter, so if you haven't completed the Exercises section yourself, then you should move to this tag now so that you're up to date. For more detailed instructions, see the To get the most out of this book section in the Preface.

This type of callout means that the code base now contains additional changes since the last edits covered in the book. It often happens at the start of each chapter when the preceding chapter had exercises, but it also happens when the code base skips ahead with changes that are uninteresting or not related to the content of the book.

When you see this callout, you have two options:

You can choose to check out the new tag and start a new branch, starting afresh. In this case, the instructions are the same as before, except now you'd need a different branch name from your existing branch:

git checkout tags/load-available-time-slots

git checkout -b load-available-time-slots-mine

You can choose to continue working on the branch you have. This could be because you've been creative and made changes that aren't covered in the book (which I fully support). In this case, 

git diff

and

git merge

are your friends. You will want to review the changes in the latest tag, and then git merge them in. You may need to handle conflicts:

# to view the differences in the new tag

git diff tags/load-available-time-slots

# to auto-merge those differences into your branch

git merge tags/load-available-time-slots

The second option is not entirely risk free, mainly due to the Exercises section at the end of each chapter.

Solving the exercises

Almost every chapter has an Exercises section at the end. These exercises are designed to give you ideas for how you continue practicing what you've learned. They have already been solved in the GitHub repository so you can see how I've solved them. The next chapter always starts from the point where I've solved the exercises.

Should you choose to solve the exercises—which I encourage you to do—then the likelihood is that you'll have solved them in a different way than I would have. Unfortunately, this might leave you in merge hell when you begin the next chapter.

If you find yourself in this situation, I suggest you first study the differences between your approach and mine. Think about how they differ and the relative merits of each. (Do not think that mine will be any better than yours.)

Then, ensuring you've committed and successfully stored your code, move to a new tag and a new branch, starting again.

In other words, be pragmatic and don't spend an inordinate amount of time fighting the system. It's better to keep moving and not get stuck or frustrated.

Pro tip: always keep your exercise solutions in a separate commit. When you move on to the next chapter, branch from your pre-Exercises commit and merge in the official exercise solutions instead.

Debugging when things go wrong

Should you get stuck, or your tests fail in a way that you weren't expecting, feel free to launch the application and see what the console is telling you. Add in console.log statements to help you debug.

The best defense against getting stuck is committing early and often. Any time you have a working feature, commit it!

Download the example code files

In addition to the GitHub repository, if you prefer you can download the example code files for this book from your account atwww.packt.com. If you purchased this book elsewhere, you can visitwww.packt.com/supportand register to have the files emailed directly to you.

You can download the code files by following these steps:

Log in or register at

www.packt.com

.

Select the

SUPPORT

tab.

Click on

Code Downloads & Errata

.

Enter the name of the book in the

Search

box and follow the onscreen instructions.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

WinRAR/7-Zip for Windows

Zipeg/iZip/UnRarX for Mac

7-Zip/PeaZip for Linux

We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

Conventions used

There are a number of text conventions used throughout this book.

CodeInText: Indicates code words in text, React component names, test names, directory names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: "In test/domManipulators.js, add the following new property to the return object of createContainer."

Any command-line input or output is written as follows:

$ mkdir css

$ cd css

Bold: Indicates a new term, an important word, or words that you see onscreen. For example, words in menus or dialog boxes appear in the text like this. Here is an example: "The final test for the Undo button is to check that it dispatches an UNDO action when it is clicked."

Warnings or important notes appear like this.
Tips and tricks appear like this.

JavaScript syntax

As much as possible, the book aims to be consistent with its approach to syntax. There are some choices that may be contentious but I hope that they won’t put you off reading. For example, I use semi-colons throughout. If you’d prefer to not use semi-colons, please feel free to ignore them in your own code.

Prettier

I have used Prettier to format code samples, and its configuration is set within package.json in each of the appointments and spec-logo projects. Here it is:

"prettier": { "singleQuote": true, "printWidth": 67, "jsxBracketSameLine": true}

Feel free to change this to your own configuration and reformat files as you see fit. The line width of 67 characters is particularly short but ensures that, for the most part, code snippets do not suffer from line breaks.

The one place this is not true is with test descriptions:

it('passes from and to times through to appointments when retrieving appointments', async () => {

In these cases, although the text is printed over two lines, you should enter it on one line only. If you are copy and pasting code samples from the electronic version of this book, you’ll need to remove the extra line breaks that are inserted by your editor.

Directory structure

Finally, both code bases suffer from a distinct lack of civilized directory structure. I hope this isn’t an issue for you; I just didn’t want to spend time discussing building directories and moving files when it isn’t the focus of the book.

Get in touch

Feedback from our readers is always welcome.

General feedback: If you have questions about any aspect of this book, mention the book title in the subject of your message and email us at [email protected].

Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packt.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.

Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.

If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.

Reviews

Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!

For more information about Packt, please visit packt.com.

Section 1: First Principles of TDD

This section is an exploration of the principles of test-driven development. You'll test drive the rendering of data and the loading of data from our server, and in the process, you'll build your own test helpers that help to simplify and accelerate your testing. By the end of the section, you'll have a working application.

This section includes the following chapters:

Chapter 1

,

First Steps with Test-Driven Development

Chapter 2

,

Test-driving Data Input with React

Chapter 3

,

Exploring Test Doubles

Chapter 4

,

 

Creating a User Interface

First Steps with Test-Driven Development

This book follows a simple format: it's a walk-through of building React applications using a test-driven approach. We'll touch on many different parts of the React experience, including building forms, composing interfaces, and animating elements. We'll also integrate React Router, Redux, and GraphQL, all guided by tests. The focus isn't on how these features of React work, but rather on how to test them and make sure you're using them with confidence.

Modern JavaScript programmers rely heavily on packages that other people have developed. This allows us to concentrate on innovating, not reinventing, the wheel. The downside, however, is that we don't always have a full understanding of the technologies we’re dealing with. We simply don't need to learn them.

Among other things, Test-Driven Development(TDD) is an effective technique for learning new frameworks and libraries. That makes it very well suited for a book on React and its ecosystem. This book will allow you to explore React in a way that you may not have experienced before.

If you're new to TDD, some of the steps outlined may leave you scratching your head. You may find yourself wondering why we're going to such Herculean efforts to build an application. There is tremendous value to be gained in specifying our software in this way. By being crystal clear about our requirements, we gain the ability to adapt our code without fear of change. We gain automated regression testing by default. Our tests comment our code, and those comments are verifiable when we run them. We gain a method of communicating our decision-making process with our colleagues. And you'll soon start to recognize the higher level of trust and confidence you have in the code you're working on. If you're anything like me, you'll get hooked on that feeling and find it hard to work without it.

Sections 1 and 2 of this book involve building an appointments system for a hair salon—nothing too revolutionary, but as sample applications go, it offers plenty of scope. We'll get started with that in this chapter. Sections 3 and 4 use an entirely different application: a Logo interpreter. Building that offers a fun way to explore more of the React landscape.

This chapter, and in fact this whole book, takes a first principles approach to React. We start with minuscule steps to slowly uncover the TDD story. We'll prefer rolling our own code to using libraries and packages. We will start from an empty directory and begin building out our application, test by test. Along the way, we’ll discover a lot of the fundamental ideas behind test-driven development and React.

The following topics will be covered in this chapter:

Creating a new React project from scratch

Displaying data with your first test

Refactoring your work

Writing great tests

Rendering lists and detail views

Technical requirements

Later in this chapter, you'll be required to install Node Package Manager (npm) together with a whole host of packages. You'll want to ensure you have a machine capable of running the Node.js environment.

You'll also need access to the command line.

In addition, you should choose a good editor or Integrated Development Environment (IDE) to work with your code.

Creating a new React project from scratch

There's a standard template for creating React apps: the create-react-app application template. This includes some standard dependencies and boilerplate code that all React applications need. However, it also contains some extra items such as favicon.ico, a sample logo, and CSS files. While these are undoubtedly useful, having them here at the very start of a project is at odds with one of the test-driven developer's core principles: You Ain't Gonna Need It (YAGNI).

This principle says that you should hold off adding anything to your project until you're really sure that it's necessary. Perhaps that's when your team adds a user story for it into the iteration, or maybe it's when a customer asks for it. Until then, YAGNI.

It's a theme that runs throughout this book and we'll start right now by choosing to avoid create-react-app. You can always start every JavaScript project from scratch, and there's a certain joy to be found in going over the basics each time.

Installing NPM

We’ll be making extensive use of the npm command-line tool and the Node.js execution environment. Each time you run your tests, which will be very frequently, you'll be required to run an npm command.

Toward the end of the chapter, we'll also use npm to package our application.

You can find out if you already have it installed on your machine by opening a Terminal window (or Command Prompt if you’re on Windows) and typing the following:

npm -v

If the command isn’t found, head on over to the Node.js website for details on how to install. The URL is included at the end of this chapter.

The npm program knows how to update itself, so if it's installed, I recommend you ensure you’re on the latest version. You can do this on the command line by typing this:

npm install npm@latest -g

I'm using version 6.9.0 to write this book. If you have any issues with the code samples contained here, differing NPM versions could be one of the causes, so please bear that in mind as you continue.

Yet another resource negotiator (YARN) is an alternative to NPM, and I won’t hold it against you if you choose to use it. There are only a handful of npm commands in this book—I assume that if you’re sticking with YARN, then you’ll already know how to convert npm commands to yarn commands.

Creating a new Jest project

The Git tag for this section is starting-point. It doesn't contain any code; just a README.md file. If you want to follow along using the book's Git repository then you should ensure you've branched from this tag. Detailed instructions from doing that are in the Getting started before Chapter 1 section of the Preface.

Now that NPM is installed, we can create our project:

If you're following along with the book's Git repository, open a Terminal window and navigate to the repository directory that you cloned in the

Getting started before Chapter 1

section of the

Preface

. Otherwise, simply navigate to your local projects directory.

Create a new directory using

mkdir appointments

and then change to it using

cd appointments

.

Enter the

npm init

command,

which begins the process of initializing a new NPM project and generating a

package.json

file for you.

The first questions ask you to provide a package name, version, description, and an entrypoint. Since we're building an appointments system, you can call it

appointments

. Accept the default version (by just hitting

Enter

), and enter a description of

Appointments system

. You can accept the default entrypoint too.

Next, you'll be asked for a

test

command, f

or which you should type in

jest

. This will enable you to run tests by using the

npm test

shortcut command.

Don't worry if you miss this; you can set it afterward by adding "test": "jest" to the scripts section of the generated package.json.

You'll be asked to specify a repository, which you could just set as

example.com

for now. If you don’t fill these fields in,

npm

will print warnings every time you run a command.

You can accept the defaults for everything else.

You may wonder why we filled out the repository field. TDD loves fast feedback cycles. Prioritize cleaning your screen and command outputs of as much noise as possible. Any time you see something that is destroying clarity, either fix it right then and there, or put it as an action at the top of your to-do list. In this particular case, you could also add "private": true to your package.json, instead of setting the repository field.

Hit

Enter

on the remaining

questions to finish the initialization process.

Install Jest using

npm install --save-dev jest

.

You will see the bottom line of your Terminal fill up with a fast-changing stream of package information as NPM installs dependent packages (a paltry 553 packages at the time of writing). You may see some warnings depending on the platform you are installing on, but these can be ignored. Once complete, you should see this:

npm notice created a lockfile as package-lock.json. You should commit this file.+ [email protected]+ added 553 packages from 373 contributors and audited 849842 packages in 16.304s+ found 0 vulnerabilities

Commit early and often

The second sentence of that command output (You should commit this file) is a good cue for us to commit for the first time.

TDD provides natural breakpoints for you to commit code. If you’re starting out with TDD, I’d recommend committing to source control after every single test. That might seem like overkill for your projects at work, but as you're learning, it can be a very effective tool.

If you've ever watched The Weakest Link, you'll know that contestants can choose to bank their winnings at any time, which decreases their risk of losing money but reduces their earning potential. With git, you can use git add to effectively bank your code. This saves a snapshot of your code but does not commit it. If you make a mess in the next test, you can revert to the last banked state. I tend to do this after every test. And, unlike in The Weakest Link, there's no downside to banking!

Committing early and often simplifies commit messages. If you have just one test in a commit, then you can use the test description as your commit message. No thinking is required.

If you're using git, use the following commands to commit what you’ve done so far:

git init

echo "node_modules" > .gitignore

git add .

git commit -m "Blank project with Jest dependency"

Bringing in React and Babel

Let's install React. That's actually two packages:

npm install --save react react-dom

React makes heavy use of JavaScriptXML (JSX), which we need Babel to transpile for us. Babel also transpiles our modern ES6 and ES7 constructs for us.

The following information is accurate for Babel 7. If you're using a later version, you may need to adjust the installation instructions accordingly.

Thankfully, Jest already includes Babel, so we just need to install presets and plugins:

npm install --save-dev @babel/preset-env @babel/preset-reactnpm install --save-dev @babel/plugin-transform-runtime

npm install --save @babel/runtime

A Babel preset is a set of plugins. Each plugin enables a specific feature of the ECMAScript standards, or a preprocessor such as JSX.

The env preset brings in essentially everything possible. It should really be configured with target execution environments. See the Further reading section at the end of this chapter for more information.

We need to enable the packages we've just installed. Create a new file, .babelrc, and add the following:

{ "presets": ["@babel/env", "@babel/react"], "plugins": ["@babel/transform-runtime"]}

With that, you're all set to write some tests. You may wish to check in at this point.

Displaying data with your first test

The Git tag for this section is appointment-first-name.

In this section, we'll discover the TDD cycle for the first time.

We'll start our application by building out an appointment view. We won't get very far; the tests we'll create in this chapter will simply display the customer who made the appointment. As we do so, we'll discuss the TDD process in detail.

We'll build a React functional component called Appointment. It is used for displaying the details of a single appointment in our system. The component will be passed in a data structure that represents Appointment, which we can imagine looks a little something like this:

{ customer: { firstName: 'Ashley', lastName: 'Jones', phoneNumber: '(123) 555-0123' }, stylist: 'Jay Speares', startsAt: '2019-02-02 09:30', service: 'Cut', notes: ''}

We won't manage to get all of that information displayed by the time we complete the chapter; in fact, we'll only display the customer's firstName, and we'll make use of the startsAt timestamp to order a list of today's appointments.

But before we get on to that, let's explore Jest a little.

Writing a failing test

What exactly is a test? We'll discover that by writing one. In your project directory, type the following commands:

mkdir test

touch test/Appointment.test.js

Open the test/Appointment.test.jsfile in your favorite editor or IDE and enter the following:

describe('Appointment', () => {});

The describe function defines a test suite, which is simply a set of tests with a given name. The first argument is the name (or description) of the unit you are testing. It could be a React component, a function, or a module. The second argument is a function inside of which you define your tests.

All of the Jest functions are already required and available in the global namespace when you run the npm test command. You don't need to import anything.

For React components, it's good practice to give your describe blocks the same name as the component itself.

You should run this code right now in the Jest test runner. It will give us valuable information about what to do next. You might think that running tests now is pointless, since we haven't even written a test yet, but with TDD, it's normal to run your test runner at every opportunity.

On the command line, run the npm testcommand:

> [email protected] test /home/daniel/work/react-tdd/ch1> jestFAIL test/Appointment.test.js● Test suite failed to runYour test suite must contain at least one test. at node_modules/jest/node_modules/jest-cli/build/TestScheduler.js:225:24Test Suites: 1 failed, 1 totalTests: 0 totalSnapshots: 0 totalTime: 0.917sRan all test suites.npm ERR! Test failed. See above for more details.

You can see Jest helpfully tells us Your test suite must contain at least one test. Test-driven developers rely heavily on listening to the test runner and what it tells us. It usually tells them exactly what to do next. In this case, it's telling us to create a test. So, let's do that.

Where should you place your tests?If you do try out thecreate-react-apptemplate, you’ll notice that it contains a single unit test file,App.test.js, which exists in the same directory as the source file,App.js. I don't recommend mixing production code with test code. For a start, it isn’t the conventional unit-testing approach, which uses two separate directories for production code and test code. More importantly, however, it’s likely that you won’t have a one-to-one mapping between production and test files.

Writing your first expectation

Change your describe call to this:

describe('Appointment', () => {

it('renders the customer first name', () => {

});

});

The it function defines a single test. The first argument is the description of the test and always starts with a present-tense verb, so that it reads in plain English. The it in the function name refers to the noun you used to name your test suite (in this case, Appointment). In fact, if you run tests now, with npm test, remember, it should make sense:

PASS test/Appointment.test.js Appointment ✓ renders the customer first name (1ms)

You can read the describe and it descriptions together as one sentence: Appointment renders the customer first name. You should aim for all of your tests to be readable in this way.

As we add more tests, Jest will show us a little checklist of passing tests.

You may have used the test function for Jest, which is equivalent to it. Since we’re doing behavior driven development style of TDD, you should stick with it.

Empty tests, such as the one we just wrote, always pass. Let's change that now. Let's add an expectation to our test. Change test to read as follows:

it('renders the customer first name', () => {

expect(document.body.textContent).toMatch('Ashley');

});

This expect call is an example of a fluent API. Like the test description, it reads like plain English. You can read it like this: I expect document.body.textContenttoMatch the stringAshley.

Although it might look complicated, it's quite a simple idea: each expectation has an expected value that is compared against a received value. In this example, the expected value is Ashley and the received value is whatever is stored in document.body.textContent.

The toMatch function is called a matcher and there are a whole lot of different matchers that work in different ways. In this case, the expectation passes if document.body.textContent has the word Ashley anywhere within it.

Each individual test can have as many expectations in it as you like, and we'll see examples of multiple expectations in a test later in this chapter.

Before we run this test, spend a minute thinking about the code. You might have guessed that the test will fail. The question is, how will it fail?

Let's run test now, with npm test, and find out:

FAIL test/Appointment.test.js Appointment ✕ renders the customer first name (10ms) ● Appointment › renders the customer first name expect(received).toMatch(expected) Expected value to match: "Ashley" Received: "" 1 | describe('Appointment', () => { 2 | it('renders the customer first name', () => { > 3 | expect(document.body.textContent).toMatch('Ashley'); | ^ 4 | }); 5 | }); 6 | at Object.toMatch (test/Appointment.test.js:3:39)

There are four parts to the test output that are relevant to us:

The name of the failing test

The expected answer

The actual answer

The location in the source where the error occurred

All of these help us to pinpoint where our tests failed: document.body.textContent is empty. This isn't surprising really, since we've not done anything to set the body text.

But, hold on a second. Where did document.body come from? No one defined that yet. Shouldn’t we expect the test to fail with an error saying that the document is undefined?

Jest magically includes a DOM implementation for us, which is why we have access to document and document.body. It uses jsdom, a headless implementation of the DOM. We can do test browser interactions on the command line, which is much simpler than involving a browser in our work.

In Jest lingo, this is called the Jest environment and it defaults to jsdom