- In this lesson, we're going to take a detailed look
at how to test React applications using Jest.
We're going to look at two different testing libraries
and there's a library called Enzyme.
Enzyme allows you to look inside a component
and check its internal details.
So for example, you can look at the properties,
or the parameters, if you like,
that were passed into a component,
the state the data that it maintains across rendering,
like a counter,
something called effect hooks,
an effect hook is a react mechanism.
It's kind of like a way of invoking another function
after every time the component's rendered.
So every time the component's rendered,
you can say call this other function
to do some additional work,
maybe to update data in local storage
or something like that.
So anyway, with Enzyme, you have full access
to the internal details of the component,
and you can do white box testing.
There's another library called React Testing Library,
which looks at the component from the outside.
So, it tests the component's overall effect.
What does it look like to the user's perspective?
So this is more like black box testing from the outside.
So both of these have a role to play.
This is a bit more like unit testing,
and this is a bit more like kind of user acceptance testing.
Does it look right from what the user is going to perceive?
So React Testing Library doesn't have access
to the internals of the component,
but it can see what it looks like
after it's been rendered from the user's perspective.
Both of these different testing libraries
have an important role to play when you test and react.
So what we're going to do, for the sake of consistency,
we have quite a lot to cover in this lesson,
so what I've done is I've written
a single sample application,
and it's gonna be the same application
that we use throughout the lesson for consistency.
So before we look at how to test it,
I thought it'd be a good idea to actually explain
what the application does so you can understand it,
and then we'll have a look at testing it later.
So if you go into the demo folder,
so we are in lesson 10 now,
if you go into sample application in there,
I've got a demo app tool.
I generated this using the Create React App tool.
And this demo application is a reasonably interesting
React application with several components,
and a use of interface that is sufficient for us
to understand what's involved in a realistic scenario.
So I've opened that project in the code editor.
Okay, so I'm gonna give you a quick overview
of what the code looks like in the next few minutes.
Before we do that, I thought it'd be a good idea
to actually see what the application looks like
from the user's point of view.
So, open up a command window,
and go into the demo app folder,
sample application demo app,
and then run NPM install, or yarn install,
to install the packages,
and then do an NPM start to start the application.
Okay, and it'll compile the application
from TypeScript into JavaScript.
Babel will convert all of the JSX into pure Java,
and then it'll open up a web browser.
Sorry, it'll open up a web server
and display it in a web page.
So when you do that,
eventually, it'll take about five minutes to do all of that.
I've done it already.
This is what it's gonna look like
when you run the application.
So here we go,
it's rich enough for us to have something tangible
to get our teeth into.
What I've got is some simple data,
as I'll show you in a moment.
I've defined a class called product,
and each product has a description and a price,
and the number of units in stock,
imagine it was like an online retailer.
This shop sells skis.
A pair of skis cost 1000 pounds, it's quite expensive,
and there are five skis in stock, or five pairs of skis.
The shop also sells ski boots,
they come in at 250 pounds a pair,
and there were four pairs in stock,
and ski goggles is the third item.
So my shop doesn't sell many items, but it's getting there.
And then at the bottom, it calculates the total value
of the shop's stock.
So if carbon skis cost 1000 pound each,
and there were five of them, that's 5,000 pound.
That's another 1000 pound,
so that's 6,000 pound.
That's another 1000 pound,
7,000 pound is the total value,
which is calculated based on
multiplying the price by the stock,
and then just adding them all up.
Okay? So that makes sense?
So let's start looking at the code
to see how it's implemented.
Once we understand the code,
then we can see how to test it in the rest of the lesson.
So first of all, all of this code is in the source folder.
So in the source folder I have a class called product,
okay, product item, there we go.
It's a regular TypeScript class.
It has a constructor.
You pass in the description, like goggles,
the unit price, and how many in stock.
And if you haven't seen this syntax before in TypeScript,
when you have a constructor,
and you annotate the parameters with public,
then these parameters actually become fields in the class.
It's a shorthand syntax,
for declaring fields and for copying parameters into them.
So a product will have a description field,
which is public, initialized by that parameter,
and a price data number and an in stock data number.
Those values are actually stored implicitly,
and copies those values into the object.
Okay, so that's my product item class.
All it does,
it has nothing to do with user interface,
it just stores the data for a product item.
Okay, a simple class to hold product data.
Nothing to do with React, just a simple data class.
Right, so in a React application,
you've normally got a top level component called app,
the root component that gets things going.
So let's have a look at that.
First of all, from the very top we have the index TSX file,
which renders the application component.
The application component is defined in app TSX.
Let's have a look at that.
So what I've done here is I've set up some sample data.
I've set up an array of product item.
I've created three product items as we just saw.
And then what I do is in order to render the application,
typically the application component
doesn't actually do much,
it just kicks off some other component to do the rendering.
So just like in a Java application, or C++, or C#,
the main function doesn't do much,
it just kicks off some other function to do the work,
and that's what I've done here.
All the application component does,
is to render another component called product list.
And the product list component receives a property
called products,
and that will be the array of products I've just seen.
So that array of products
will be passed in as a property
into the product list component.
Basically, the application component says
render that list of products.
This component knows how to render a product list.
So the product list component,
it receives a list of products,
and it displays them in that list that we saw.
Remember what we were looking at?
Basically the product list component
is going to display this list of products.
So let's have a look at the product list component next,
and it is here.
So the product list component,
so TypeScripts and backs starts to get a bit ugly.
So I'll just run through what's going on here.
Ultimately, if you remember,
components just receive a single object.
Okay, but typically you'll want to gain access
to one of the properties inside the object,
or maybe multiple properties.
So you could say if that object had a property
called A, B, and C and you want to access them,
you can use destructuring to say something like this,
A, comma, B, comma, C,
okay, take the incoming object and extract those properties.
The reason that type script is complaining,
is because it needs to know what type are those properties?
So you have to say, oh, I can't believe it,
I've gotta tell you the types of each property?
Okay, well A is a number,
and B is a string,
and C is a number.
So we have that kind of syntax in type script.
An object gets destructured, extract those properties,
TypeScript needs to know what those property types are.
This is a hypothetical example,
but that explains the syntax.
So if I revert to what we had originally,
the object that was passed in
had a property called products,
and that products property was an array of product item.
Remember from my application component,
I passed in a products property,
it was an array of products.
Okay, so the products,
variable, is an array of product item.
It's an array, if the length of the array is zero,
then it displays this.
It'll just say, instead of displaying a list,
it'll just say no products in stock.
Well, we have three products,
so it displays a heading.
Remember when you're in JSX or TSX, you have
to enclose JavaScript inside curly brackets to evaluate it.
So there are three products in stock.
There are three products in stock, each product,
how do you want to display each product?
Well, I'm gonna defer that to another component.
I'm gonna actually do this.
I'm gonna say for each, loop through that array,
okay, so each time round this,
the map function is gonna call this Lambda.
This Lambda will be involved with the first product,
then the second product, then the third product.
Okay, so P, will be a product item.
And what we do, is we convert it into a product component.
This is really common in React.
You have an object, or you have an array,
and you iterate through the array to get each object,
and then you convert it into something that can be displayed
for each product, render it like this.
Okay, each product will be rendered
by the product component.
Whenever you have a list of things,
React wants there to be like a key,
just to certain element zero, element one, element two,
so that's just a react mechanism.
And then here the spread operator,
if you remember what the spread operator does,
it basically unpacks the object into its constituent parts.
So if the product item had a property called description,
then it'll be, this, will basically say,
okay then, let's pass in a description property,
which will be the product's description.
Okay, and it does it for the next property,
so the next property was-
what was the next property in my product item?
Price.
Okay, so it'll then say let's pass in a price property,
which is the value of the product's price.
Because we are in TypeScript,
it knows that each element in the array is a product item,
so we get Intellisense, cool isn't it?
One of the reasons for using TypeScript.
And so on for the units in stock,
units in stock is going to be equal
to the value of the product's unit in stock.
Okay, so at this point I might be tempted
to kind of split it onto separate lines,
because it's quite difficult.
In fact, I think I'll indent that a bit more as well.
You want your code to be readable,
because you're gonna have to maintain this,
for years going forward, potentially.
Okay, so there we go.
I might put that there as well.
So basically for each product, render the product component,
and pass in a property called
description, price, and in stock.
That was equivalent to just doing
dot, dot, dot, P.
Okay, that is equivalent to doing that.
It'll basically automatically expand each of its properties
into a separate parameter, like that.
Okay, so I can just shorten it
back to what we had before then,
in that case, that might be easier on the eye-
like that.
So what does the product component do?
Well, the product component renders one product,
and it renders it like this,
all it knows about is how to render one product.
So let's have a look at the product component,
we're almost done here now.
The product component, it receives,
basically it receives an object that has a price property,
a description property, and an in stock property.
In other words, it receives a product item object,
and it says, okay display it with a heading,
and a price, and an in stock, and it has a CSS class.
Remember if you wanna set a CSS class in React,
you can't say class,
because that's a keyword in JavaScript.
In Reactive you've gotta say class name.
So there's a class,
a CSS class, somewhere called product item.
What I would normally do at this point,
I'd say, well where is that CSS class defined?
Is there some kind of CSS import here?
No.
So, it's not as if product has its own CSS file,
so it must come in somewhere else.
So maybe there's an index dot CSS that defines the class,
and there it is.
Okay, so it displays each product item in a blue background,
in a white font, in a nice large font size.
Okay, so that was one product being displayed.
If I go back to product list,
it will iterate through all my products
and display each product.
And then at the bottom, it displays the total value.
So I've actually put that into a separate component.
You do this a lot in React.
Whenever you've got a bit of HTML that's cohesive,
consider putting that into a separate component
to encapsulate it.
So I have another component called total value,
because it's quite complicated,
you have to calculate the total value of all the products.
That's not a trivial thing.
So I've put it into a separate component.
So I rendered the component here.
If you think about it, to calculate the total value,
you've gotta give it all the products,
so it can multiply and add.
So I pass in the product list into total value,
and here it is.
It receives an object of products, a product item array,
which contains an array of product item.
For each product item,
what I wanna do is to calculate the line cost, if you like.
I wanna multiply, for each product,
the price by the number in stock.
And that would give me the value
of all of my skis that that I own.
Okay, so that's what I do.
I say for each product,
take the product, multiply its price and its stock.
Okay, and then, so that'll give me the line cost,
and then what I do is I basically add them all together.
There's a very handy function in JavaScript called reduce.
And what you do is you give it two parameters,
and it's like an accumulator.
It takes two parameters
and it reduces them into a single result.
So what happens is it takes in,
T, is the current total so far,
and C, is the next value, if you like.
So first time this function's gonna be called three times,
once for the first product, then the next product,
then the next product.
First time it calls this function,
it'll pass in zero,
as the initial value for the total to bootstrap it.
And then it'll pass in
the price multiplied by the stock for the first product,
the cost of the first product.
It adds them together, and that running total
then gets passed in to the next invocation.
So every time you call this function,
it'll calculate the next total,
and pass it in to the next function call
to accumulate the values.
Eventually it'll give you back the total value,
which I display with the CSS class of orange,
I display the total value on the webpage.