Angular 14 added a long-awaited feature: standalone components. As the name implies, you can build these components independently without adding them to a module’s declarations. However, to unit test these components, we need to make some changes to the typical boilerplate we use when testing components. Particularly with the way we configure the dependency injection system to be able to provide mocks to our testing environment.
Creating a Basic Standalone Component
Just like regular components, we can use the Angular CLI to generate a standalone component along with all the typical boilerplate files and code needed.
ng generate component <your-component-name> --standalone
Or with the shorthand:
ng g c <your-component-name> --standalone
Depending on how your project is configured, you should now have the typescript file, the HTML file, the SCSS file, and the spec file all available in your project. If we look at the typescript file for our component, you will notice some slight differences in how the @Component
decorator is configured.
The standalone: true
property is self-explanatory and expected. But the other interesting line is imports: [CommonModule]
. This imports
field is where we can bring in any other standalone components, pipes, or modules that our component needs. In this case, the Angular CLI has already imported the CommonModule
for us, home to things like *ngFor
and *ngIf
.
If we go into the app.component.html
file and try to use our standalone component, we will get an error when running our app that says our component is not a known element. Standalone components may not need to be added to any module’s declarations, but they do need to be imported anywhere they will be used. This is easy to fix. We can go into the AppModule
and add our component to the imports
list:
Now, your application should build successfully using your new standalone component.
Mocking Dependencies
Unfortunately, mocking dependencies for standalone components requires a slightly different setup than traditional components, but it is still fairly straightforward.
Let’s say that our standalone component depends on a service in our project, ExampleService
. To mock this dependency in our test, we must use the overrideComponent
method on the TestBed
. This method will allow us to remove the default providers and provide our mocks. Our test setup should now look something like this:
Simplify with Standalone Components
Standalone components are a great way to simplify an Angular application. I am trying to understand why the traditional way of mocking dependencies for components does not work for their standalone counterparts. However, I am confident there’s a technical reason the Angular team had to implement it this way. Hopefully, in the future, they can coalesce these two methods into a unified strategy.