Here are part 1 and part 2 for some context.

#What is a Smart Component

One of the recommended ways of structuring Angular applications is by using something called Smart and Dumb Components. Or Container and Presentation Components. They both mean the same thing:

You structure your app by having components that act as orchestrators. They use services, get data, process events, decide what to put on screen. These are the Smart/Container components. You use small reusable components that don’t do any processing. They are in charge of showing data, bubbling events up, styling etc. These are the Dumb/Presentation components.

🧪 Testing the Dumb component is pretty straight forward. It’s even simpler than what we did while testing the FavoriteMovies component here. You just have to check that the correct information is displayed and that the events are bubbled up. You should not have to worry about any dependencies, modules etc.

#Where we left off

So, in the previous articles we learned how to test a regular component and an HTTP Service. Let’s take this one step further by having a look at a Smart Component. We were using Angular with Jest, so let’s keep using that. We don’t wanna change frameworks every other week 😅.

#Architecture considerations

Now, before we go into code, let’s think a little about what we want our structure to be.

I propose this: let’s have one FavoriteMoviesComponent that shows all the favorite movies. This component will show 0 -> n FavoriteMovieComponents. This component will also show a search-movie section where a user would be able to search and add movies to his favorites list.

So, responsibility wise, the FavoriteMoviesComponent will know how to add a movie, delete a movie, show all movies.

Any objections? No? Good! Glad we agree.

Let’s proceed.

#Generate the Dumb Components

From our scenario from above, we can identify 2 new components that are needed: The FavoriteMovie(Dumb) and the SearchMovie(let’s say Smart). To keep this post (relatively) short, we won’t care about their actual implementation. We just know they look like this:

#Current state of the FavoriteMovies Component

Right now we already show all the favorite movies in our component template, but without the help of a reusable component. So, we want to refactor this part:

We want to:

Use our new FavoriteMovie component instead of just a div Use our new SearchMovie component on top of all this Listen to events from these components and act accordingly

So, let’s do this! Let’s use our new Dumb Component!

Waaaaaaaait! What’s the title of the article? TDD meaning TEST Driven Development. Remember? Write tests, see them fail and THEN make them pass.

Good, let’s add a test that checks that our FavoriteMovies (Smart) Component shows the correct amount of FavoriteMovie (Dumb) Components.

Now, we run it aaaaand:

Failure! Don’t worry. It was meant to be. The error is pretty clear. It expected 3, it got 0. Now, let’s fix this.

As you can see, we replaced the <div> with our reusable component. Now when we run the test again, we get this:

This means that our TestModule does not know what the <kpd-favorite-movie> tag is. We have a couple of options.

We can add — schemas: [ NO_ERRORS_SCHEMA ] — to our TestBed configuration. This tells it to ignore anything it doesn’t know. I don’t really like this since it ignores part of the core responsibility of a Smart Component. We can add the FavoriteMovieComponent to the declarations array in the TestBed Configuration. I don’t like this because if your Dumb component has dependencies, or if you rely on other Smart Components as well, you suddenly have to provide a ton of extra services and take care of those. This just pollutes 💨 your spec file since it’s not really related to the responsibility of the component you are currently testing. We can use a library like ng-mocks to declare a MockComponent. This works for Components, Pipes, Directives etc. This will give you a fake component that has the shape of the actual component, without it’s implementation.

As you probably figured out, I usually go with the 3rd option.

So, after

yarn add ng-mocks

we add the mock component to our declarations:

And now, our tests pass:

Great! We have our first test that checks how our Smart Component uses Dumb Components. But it this enough?

#Checking the details

Is this enough? Not really. Think about it. This test checks that the components are on the page, but doesn’t really check that they receive what they should. As a matter of fact, they don’t receive anything.

Let’s quickly complete the previous test.

Here we check that all the inputs of the FavoriteMovie components sum up to all the favorite movies that we want to show. Of course, this is just one way of checking it. We could also just iterate one by one and check that it exists etc. Your choice on how to do this. The important thing is to check it.

Now, what do we do? We run the tests!

No surprise here. It expected to pass the movies as inputs, but nothing was passed. The fix is pretty easy:

Running the test again shows us this:

That GREEN 🍏 man! Good stuff.

#What about the events?

You’re right! We need to check the events as well. So, our FavoriteMovie component will emit an event when a movie is deleted. Our Smart component needs to listen to that and tell the FavoriteMoviesService to delete the specified movie. Again, we covered the testing/implementation of the HTTP Service here, so we won’t go through that again.

As usual, we start with the test:

A couple of things are happening here:

We spy on the delete method of the service We get the component that we want to emit a delete event We emit the delete event We check that it was properly handled to the service

Now, running the test is of course: RED 🔴

Next station: GREEN! 🍏

How do we get there? We add the implementation. This consists of 2 steps: catching the event in the template and handling it in the component code.

☝️ Here we listen to the event on the component.

☝️ And here we tell the service that we want to delete that movie.

Now, if we run our tests again:

It’s GREEN 🍏! What a day! What a lovely day!

#Ok, now faster

So, we now have a fully tested flow with a Smart Component using a Dumb component. Let’s do the same for the SearchMovie Component.

We start with the tests OF COURSE:

So, we added the MockComponent(SearchMovieComponent) to the declarations of the TestBed config and then we wrote the tests for that feature.

The template looks like this now:

And the last piece of the puzzle, the implementation for the addMovie method:

And the test results:

WOW! Aren’t tests beautiful? 😍

And now we have a fully tested search feature(from the Smart Component point of view).

#So, about those Reusable Components

Why go through all this trouble to use the reusable components when we can just as well put everything in one template. Well, a couple of reasons come to mind:

They are super easy to test They are super easy to use in multiple pages They can/should use ChangeDetection.OnPush(big boost performance wise). Google it. They make the Smart Component easier to test and wire everything together.

#Summary

So, if you just skipped through all this wall of text( I usually do that 😅) at least keep this in mind 🧠: Reusable components are good for you, are easy to test and help a lot with performance 🏍 and maintenance.

In case you wanna know more, here are some other things I rambled about:

If you liked this article, eh, maybe follow me on twitter

#Over and out