- In an angular application
a component's HTML template can contain child components.
Typically, those child components are relevant
to us when we're testing our component.
We don't want their HTML to interfere
with what we are trying to test from our component.
So, how can we test a parent component
without having to try to predict the HTML
from all our children?
Well, the actual answer is to stub those children out.
So they don't actually render anything.
That means you can just focus on your component instead.
So we're gonna see how to do that,
how to stub out child components,
so they don't interfere with us
when we're trying to test our component.
Example, it's lesson 12 example one,
the demo application there
is actually the same application we've looked
at over the last couple of videos.
So here it is.
If you remember in there, quick reminder,
I had a component called toggle switch
which displayed a button that was on or off.
Its selector was app toggle switch.
And then we had another component called banner.
It displayed a message.
I could click on it to make it uppercase
or lowercase.
Its component selector was app banner.
So those are two children components.
And I embed them inside my top-level application component.
Here's my top-level application component
and doesn't contain much data, but the template,
app component HTML, if you scroll down to line 353,
would you believe it renders an instance of my
toggle switch component?
And it renders an instance of my banner.
Under normal circumstances, that would work absolutely fine.
In the module, for our application,
it knows about all those components.
It knows about the AppComponent, and the banner,
and the toggle switch.
So when the application starts and when angular
sees these tags in a real angular application
it'll know which components to instantiate,
and everything's fine.
I could open up a command window, go to lesson 12,
example one demo app, do an NPM install
if you haven't already done so to install the libraries
and then do an NG serve, to serve the application.
So I've done that already.
And this is what it looks like.
Here we are.
So there's the toggle switch component,
which I can turn on and off.
And here's my banner, which I can click to
display in uppercase and click to display in lowercase.
So when we are running the application full-speed
everything's fine, because our application module has
all the components at its disposal and it can render
the entire webpage.
Okay. So that's what I've just done.
Basically in my top level AppComponent, HTML,
I rendered an instance of both components.
And when I do an NG serve, those components are available
in my module and everything's fine.
I run the tests, however, then it's not so good.
Have a look at this.
I'm running just the test for AppComponent spec TS.
Okay. This is I've tested my top-level component
which contains those other two tags.
My top-level component contains the toggle switch
and the banner.
The trouble is the test doesn't know
about those other components.
When you're testing component A
it doesn't know about child components B, C, or D.
It just knows about its component itself.
So if you run the test, you get an error message.
When the application was, when the component was rendered,
my application HTML, it had a app toggle switch tag.
And basically it's saying here, in my test environment,
it doesn't know what app banner is.
When it saw the app banner syntax in my HTML template.
Basically when it
when it processed this in my application component HTML,
it didn't know in my test environment.
It didn't know what that is.
Is it a component or is it regular HTML?
What is this then?
So we get these error messages being displayed.
App banner is not a known element.
Is it an angular component?
In this case, in this this case
you should basically notify in your test module.
You should mention this component.
Maybe it was a web component, some kind of HTML element
in which case we should register it as well.
Okay. And it's complaining as well about app toggle switch.
It says, what is this thing?
You didn't tell me about this.
When you set up the test module,
you just gave me the app component.
You didn't mention anything
about toggle switch or banner.
Doesn't know,
doesn't have a clue what we're talking about.
So clearly we have to fix that.
In our test,
We have a test bed, the test bed compiles
the HTML template for our component.
When it does that, it sees these tags,
and in the test environment,
it has no clue what those tags mean.
So we need to fix it.
So, here is what you do.
You can just be stub out the components that are
causing the problem.
This is my enhanced component spec.
What I've done is I've defined a stub component like a
do nothing component for app toggle switch.
It basically says, here is a, a mock or stub component,
basically anywhere where you see this selector,
then create an instance of this mock component.
Okay. This is replaced in the actual toggle switch component
with a, with a stub implementation
which has an empty HTML template.
And likewise for the app banner, it says
if you ever see app banner, then we, you know
basically instantiate this component
which has an empty HTML template.
That fixes the problem for us now
because when my application component is rendered
it will see, you know
the angular test environment will see these tags.
And what I've just told it
in the test environment is when you see those tags,
basically create an instance of this component
and that one that have an empty HTML template
that doesn't interfere with the rest of the stuff
generated in my component.
So, I've effectively created two stub components here.
I need to add those components into my test module.
So, when my application, when my test is starting up,
in my test bed, I configure a test module.
Here are the components that are required for this test.
I give it my real app component, my stub component for
toggle switch, and my stub component
for banner stub for banner.
Okay. So that means whenever it now knows when
that tag appears to create an instance
of that component or that component.
And that means our tests can now proceed properly.
If I run the tests properly now,
then it'll all work fine without any errors.
I'm actually gonna do that in my real code, just to verify.
So in my real code have a look in app component spec.
What I've done here is I've got
I've got these statements commented out.
So I'm gonna un-comment them now
and un-comment that one as well.
So import the component decorator from angular,
set up a stub version for toggle switch,
and a stub component for banner.
When my test sweep starts,
set up a test module and declare my real app component,
and then the stub versions of the other two.
Okay. So, basically, un-comment those two lines.
And then what I'll do is I'll get rid
of the comment as well, because well, who needs comments?
Okay.
So now, my app component will render these stub components
which have empty HTML.
So, they aren't going to interfere with what gets rendered.
Okay. And these tests now should be, should work fine.
Okay. So when I run the tests
now we don't get any error message.
So that's what you can do.
This is a common technique.
When a component has children
you can define stubbed versions
of them with an empty template.
That means that the only HTML you get
is the HTML from your component.
So you can unit test it properly.