- In this section,
we're going to investigate full DOM rendering
in Enzyme using the mount function.
You give it a component and you get back a wrapper.
The mount function renders the entire DOM tree
for the component plus all its descendants,
you get full DOM rendering.
It'll render your component.
And if your component calls other components,
they will also be expanded.
And that's how it's different from the shallow function
which we looked at earlier.
When you call the shallow function from before,
it just renders the top level component.
It has child components, but it doesn't expand them.
But when you call the mount function here,
it does expand all child components.
You get back the whole DOM tree
for everything underneath this component, okay?
So that means you can test how your component
interacts with it's child components.
When you pass parameters into your child components,
do they get rendered properly as well?
The whole DOM structure is expanded.
So to show the tests, go into this folder,
lesson 10, Enzyme_FullDom.
Again, I've got a demo application.
It's the same demo application as before
but the tests are different this time.
A quick reminder what the application looks like.
If you do an NPM install,
and then do an NPM start, I've got a product item class,
I've got app component, a product list component,
a product component that displays each product
and then a total value component
which calculates the total cost.
So the example scenario is familiar.
The tests we're gonna look at now have moved on, okay?
So here's the demo app.
If you look in the source folder,
the product list component
is, again, what we're going to test,
a product list receives an array of products.
It'll either say there are no products in stock
if the array is empty or for each product
it'll generate a product element
to display one of those blue boxes
and a total value component at the end
that adds the values up.
Oh, and also a heading to say there are three products
in stock.
So again, the code we're testing is the same as before,
but the tests themselves are now going to use
the mount function as opposed to using
the shallow function from before.
Okay, so the mount function,
when you call mount, it returns a ReactWrapper.
In the previous section,
when we called the shallow function
it returned an object called ShallowWrapper.
When you call the mount function here,
it returns a ReactWrapper.
Very similar, it functions allows you to end the content
that's been rendered, find,
and then you can give it a CSS selector,
the name of an element or the CSS class
or an ID of an element.
And it gives you back a collection
of everything that matches that selector.
Okay, you can get all children for an element,
you can get back the first child, the last child,
this is similar to ShallowWrapper.
Check the properties that have passed into a component,
get the value of one of the properties with a particular key
and so on and so on and so on.
Okay, to the documentation here, Enzyme JS.
If you go to the mount web page here,
the documentation, let's take a quick look, should we?
Here we are.
This is the mount API documentation.
So again, it's quite straightforward
and very similar to ShallowWrapper.
So a little bit of an explanation here
that gives you the broad idea.
And then a detailed look and all the functions available
in this ReactWrapper object.
Find whether some condition is true,
give me back all elements that match some kind of predicate.
Okay, so very similar to ShallowWrapper.
Remember the difference, when you call mount
it expands all of your child components
so you can drill down into the descendant hierarchy
if you need to.
Okay, so here's the first test in productlist.test.tsx.
So I invoke my product list component.
I mount it.
This will expand all child components as well
but as an empty array.
Quick reminder of what that component should render
in that case.
So back in our code, my product list component,
if the array of products that we pass in,
if it's an empty array,
then what we should get back is something like that.
Right?
And not any products and not any total value, okay?
We just basically, that's all we should get back.
So let's check, right?
So mount,
again, this is not a great name for it.
A better name for this function would've been
render component plus all sub-components please.
But that's mount and see what it does.
Let's check what we get back.
If we find H1 elements that gives you back a collection.
The length of that collection, there should be one, H1.
Let's get the first H1 and let's look at the text inside it.
The text inside it should be, no products in stock,
no products in stock.
Good.
There should not be any product element
and there should not be any total value element, okay?
If I look for products and total values
in my rendered content, they should not be there
because we didn't go into that part
of the component functionality, we just went into here.
So the code we've written so far is pretty much the same
as it would've been for shallow rendering.
It starts to get a bit more interesting when products
and total values are actually rendered,
because then we can see how are they rendered
not just whether they're rendered.
Right, so here is a partial listing
where I've actually passed in real data
into my product list component.
So remember in my test,
products was an array of three products.
So my product list component is receiving three products.
Again, before we look at the test,
let's just remind ourselves what we expect
to get back first.
So here's my product list component again.
With an array of products,
we should get back an H1, three products in stock.
It should then render the product component three times.
What's different now when you call the mount function
is that it will actually expand that product.
It won't just say, oh, there's a product,
it will actually invoke that product component
and include it in my result set.
So I should get back three actual product components
actually rendered, okay?
So I should be getting back,
for each product I should be getting back that in my result.
I should be able to see a div with a product item
and the description like skis and the price and in stock.
That should actually appear in my result set.
Right, let's see what we get back then.
Interestingly, the resultant document structure
contains both the component like product
plus it's rendered content.
So you can actually get both.
You can see there should have been three product components
in my result document, okay?
So the product component is still part
of the document structure.
There should have been three product components rendered
and each product is actually expanded, okay?
So for each product,
it should basically render it like this.
So if I've got three products,
I should have three of these as well.
One for each product.
Each of those divs is basically a different product, okay?
With a certain class.
So I should have got three divs
with a CSS class of product item.
If I search for div with a CSS class product item,
I should have a length of three, okay?
So I basically got three products being rendered.
What I can then do is to say, well, let's look at each one.
This code here checks the content of the first product
and basically verifying for the first product,
did it display the correct content
that I'm expecting in my test?
Right, well, let's see.
Let's have a look at this code, right?
So there were gonna be three divs
for those three blue boxes, give me the first one.
Give me div 0.
That's the first product, I've called it product 0.
Product 0 is basically this, okay?
I'm now looking at that.
That's product 0.
And I can say in that product 0, find an H2 element,
find the first H2 and check the text.
It should be skis.
I know what data I've passed in.
I know that the first product was skis.
There should be an H2
and the text of that H2 should be skis, the description.
So I'm basically checking that this part
was rendered correctly.
So this is what you can do with the mount function.
You can forensically analyze
exactly what's been rendered if you want to.
Okay, let's check that.
There's also a price paragraph.
In my first product, let's find all paragraphs.
There are actually two paragraphs.
Did you notice?
There's a paragraph for the price
and a paragraph for the in stock.
I'm gonna check both of them.
So, first of all, let's check paragraph 0, okay?
So that would be the first paragraph
because obviously it starts to compute at zero.
Let's check that first paragraph.
Is its text a price of a thousand, okay?
I'm basically checking the test text here,
price, a thousand.
That's the first paragraph.
What about paragraph one, okay?
So that would be the next paragraph.
Its text should be in stock five.
Obviously the numbers here are hard coded
but you tend to do that when you write uni tests.
You pass in some data that's known
and then you check actual content.
It should be displaying these actual words
based on my test data that I'm passing in.
In stock should be five, okay?
So I'm checking.
Did it display in stock five correctly?
So I've got similar code for the second product
and the third product.
This ... is actually expanded in my code.
Let me show you in my actual code.
I had so much fun writing this.
We are looking at here now, aren't we?
So I've just shown you in the slide, in the PowerPoint,
I've just basically shown you a check for product 0,
that was the skis.
And then I've got exactly the same test
for the next product, the product number one,
that should have been the ski boots.
And then I've got the same test again
for product number two.
And that should be goggles.
So you can be as detailed as you want to be in your tests.
Okay, what about the last part?
That last part there is checking the total value.
Check first of all that the total value component exists.
It will be rendered with the mount function,
it will render the total value component.
Quick reminder, here's my total value component.
I'm expecting to get back a div with a total value class.
This is actually quite useful
because when I wrote this code originally,
I did actually get my algorithm incorrect
and the test found it for me
which I thought was quite useful.
So I'm basically really checking this algorithm.
Is it actually calculating the total cost properly?
According to my maths,
if you look at the actual test that I passed in,
the data that was passed in,
if you kind of multiply each number,
these two things and add them together,
it comes to 5,000 plus 1,000 plus 1,000.
7,000 should be the total cost, okay?
So I'm expecting that there should be,
I'm expecting there to be a div,
basically total value, 7,000.
So first of all,
establish that the total value component was rendered, okay?
That should then render a div with a total value class
and the text inside it should be total value, 7,000.
That's what we expect to get back from our component.
Total value, 7,000.
Okay, so there's a lot of code you can write here.
Whether you want to check things to that level of detail
is entirely up to you, but you can if you want to.
You just need to run the test now,
and fingers crossed, toes crossed, is it gonna work?
Yes.