- So far in this lesson,
we've been looking at how to use Enzyme
to test React application.
And as we've seen, Enzyme gives us full details
to the internal implementation of a component,
so that we can access its state
and its properties and so on.
The other testing library,
we're going to look at is React Testing Library,
and this has a different emphasis.
With the React Testing Library,
you can't access the internal details.
Instead, you just look at what's been rendered
from the outside.
So it's more like user acceptance testing
rather than unit testing internally.
So the example we're going to look at, it's here.
If you go into lesson 10,
go into this folder React Testing Library demo-app
similar application to before.
So we're gonna look at a few particular files
to see what's going on.
First of all, let's have a look at package.json.
So here's my demo-app, package.json.
I've added some extra dependencies
for testing library, so let's just pick these out.
We have a dependency for testing library.
Well, testing library jest-dom.
We've seen that already and testing library user-event
for simulating events.
And then testing library react.
Okay, so this is what we're gonna be focusing
on in this section.
Also, you might wanna have a look down below
because we're writing in TypeScript.
I've also got some development dependencies here
that give me TypeScript information,
that keeps the TypeScript compiler happy.
I've got type definitions
for jest-dom and for react and for user-event.
Okay, so the TypeScript compiler
will be happy knowing what data type everything is.
Okay, so that's the package.json.
The second file to look at ProductList.
Now, remember this is the component
that render does my list of products.
So I wanna remind you
what we expect to see under various circumstances.
So let's take a look that next.
So in source folder, ProductList tsx.
It's basically the same as we've seen
before the ProductList component.
It receives an array of products and a callback function.
If the minimum or the maximum value changed,
it'll call that function back after rendering.
It uses React State to remember the minimum
and the maximum value.
There's if I scroll down to the user interface part of it.
There is a text box where the user can enter a minimum value
and it'll call this function back if it changes,
if the user types a new value in.
And a text box for the user to enter a maximum value
with the callback function onChangeMax,
those functions are defined up above.
This is the same code as before.
So if the user typed in a different value for the minimum,
we change the value of the minimum value in state
and we change the value of the maximum value.
And my use effect here, my React Hook, it says,
oh, by the way, if either the minimum
or the maximum value changes call this function back.
This call back function is passed into the component
and it calls it if the minimum
or the maximum value is changed.
Okay, when I render my component,
I have to give it a callback function
like it can invoke under these circumstances.
It'll either display a bunch of products or no products,
or it'll display the products here
if there are products, right.
So we've seen that before.
Now, let's have a look at how to test it
using the React Testing Library.
So let's see ProductList test tsx,
this is where we're gonna spend the next few minutes.
So ProductList test tsx.
First of all, I have imported the testing library react.
It gives me a render function
that will allow me to render my content
into like a virtual webpage and a screen object,
which gives me access to that content
after having rendered it.
And then also the user-event library if you remember,
enables me to assimilate events like a button click
and a text box change.
Okay, so then I set up some sample data
and then I've got four tests,
which we're just gonna have a look through.
These four tests just show you
how to use the React Testing Library.
So the easiest test would be
what would be expected at back if there aren't any products,
that's the first test.
So I render my product component
and my ProductList component I should say.
I give it an empty array products
and I give it an empty callback function, okay.
So remember, we've seen this a few times now,
but when you're using jsx or tsx,
when you're in the middle of XML syntax,
you've gotta use the curly brackets
to dip back into JavaScript.
Okay, so an empty array, no products.
The callback function is an empty function.
Okay, so basically it'll call that function,
it does nothing, right.
What would we expect to get back
if we render an empty product list?
Well, we kind of know this already.
If the product list is empty
then this is the HTML that we should get back.
Okay, a div an h1, no products in stock.
Now testing library,
this is how you use it.
Remember, the render function will render
into a virtual webpage screen
is the document body property in that virtual webpage.
So basically in my document body,
find an element that has this text queryByText.
This is the function like a high-level testing
by what the user will see.
Find an element, which has this text, no products in stock.
That's a regular expression
and it's case insensitive.
Find an element with that text
and verify that such an element actually did exist.
Okay, so did my ProductList render
and h1 no products in stock?
That's what I'm testing there.
That was easy enough.
Let's go into the second test.
Second test is where I do have some products
and I should get back a list of products being displayed.
Okay, little bit more involved.
Same idea though.
Render products with a ProductList
with a actual array products.
There were three of them.
When we do that, what should we expect to get back?
Well, we should come into here in my ProductList component.
It should come into here and it should render,
or basically three products.
Plus a total value that should now be rendered.
And it is all rendered.
We just get to see the HTML after the event.
So let's see what the HTML look like.
Let's grab the document body
and let's try to find elements 3 products in stock.
Remember when you call these query functions,
it just gives you back.
It assumes there's gonna be one match.
Find an element and there must be just one
that matches this text.
3 products in stock.
Is that an element is the one element
that contains that text.
There should be one element that contains that text.
Okay, and obviously, that's going to be this element here.
Okay. Right.
Let's go back to the rest of it here.
Now get all means give me back all elements.
This is how you find headings.
Give me back a collection of all age one headings,
the query API.
This is basically the area syntax.
Find all elements that have the heading roll.
Heading in other words h2's.
How many h2 do we expect to get back?
Interesting question.
Well, let's think about it.
We've got three products.
Each product will be rendered by the product component.
The product component for each product,
it will render an h2, the product description.
So three products altogether we should find
in the resulting webpage.
There should be three elements of type h2.
Get all elements, which h2's.
The length of the collection that comes back.
There should be three h2's for the three different products.
Get the first of those h2's.
Effectively, what I'm doing here
is I'm getting this h2 here.
Okay, the h2 for the first product.
Get it's in HTML and it should be skis.
It should contain skis, okay.
When you do a regular expression match,
you're saying does the text somewhere contain skis?
The second heading should contain the text boots.
And then the third heading
or heading three starting at zero
should contain the text goggles.
Oh! And also find one element that contains this text.
The total value should be 7,000 based on the sample data
that we passed in.
Okay, so verify that there wasn't element
that contained the text 7,000.
Of course, what that's going to be the total value displayed
at the end 7,000.
Okay, so you get a feeling
for how this works with React Dom.
You're searching just for the HTML content.
And you're searching based on the kind of text
that the user sees on the webpage
rather than something more internal, right.
Two more tests to look at and then we're finished,
oh, what should happen if the user
has specified a minimum price?
Good question.
We need to emulate the user type in a minimum price,
render the ProductList with three products.
Get a text box accompanied by the minimum price label.
Right. Remember what my ProductList looked like?
There was a label that said minimum price.
I basically wanted to get the text box associated
with that label.
That's what I've done here.
Find the label minimum price
and give me back the text box associated with it.
Into that text box, simulate the user typing this. Okay.
So we're basically specifying into the minimum text box,
simulate that event as if the user had typed in 101
into that text box.
Lots of things should happen
that should filter the products just to display products
across more than 101.
But in my actual application, if I did it in reality
that's what would actually come back.
And that's what we're gonna test does come back in our test.
So we should get back two products with a total price
of 6,000 altogether, right.
That's quite exciting, isn't it?
Get all heading tools,
so each of those products had an h2, there was an h2,
there was an h2, there should be two h2,
two products that cost more than 101.
The first heading should say skis
that costs more than 100.
The second heading should say boots,
because boots also cost more than 100.
Get the element that contains total value
and it should be 6,000.
Effectively, what I'm doing here
is I'm finding this element in my total value component.
We're finding this div
and we checking that the total value is indeed 6,000.
Okay! Right!
Same idea, but specifying a maximum price.
Let's go into here.
This is gonna be our last example.
Right, so render the products.
Get the text box associated with this label, maximum price.
So again, in my ProductList there's the label maximum price,
there's the text box associated with it.
Okay, so we've got that text box
and into that text box simulate the user type in 999.
Well, in my real application, what would that actually do?
999, right.
So we should get back ski, boots, and goggles,
a total price of 2,000.
I feel like I wanna go on a skiing holiday again.
Anyway, more of that later.
So how many h2 is do we get back?
There should have been two of them.
The first h2, the first product, boots.
And the second product is goggles.
There we go.
Goggles, boots and goggles.
Essential when you go skiing.
Also skis are essential as well.
And get the element that contains
that text total value 2,000.
Verify that did actually just...
There we are, so using the React library
where using functions like this,
you'll find it elements by roll.
Like I've done here or by label text,
and then check in the value that they contain.
Very good, so all we need to do now
is to run the test and have a party
because it's worked and that's the end of the lesson.
So we've seen a lot in this lesson.
We started off looking at the basics of React testing.
And by the end of it,
we've seen quite a detailed look at Enzyme
for unit testing and then the React Testing Library
for more kind of user acceptance testing
to verify that the webpage actually looks beautiful.