DEV Community

Rudolf Olah
Rudolf Olah

Posted on

Angular Testing Nested Components and Components that Rely or Use Other Components in Their Templates

You have two Angular components:

  • HomeComponent
  • HelloComponent

The template for HomeComponent looks like this:

<h1>Hello!</h1>
<app-hello name="Rudolf"></app-hello>
Enter fullscreen mode Exit fullscreen mode

The component definition for HelloComponent looks like this:

@Component({
  selector: 'app-hello',
  // ...
)
export class HelloComponent {
  @Input() name;
}
Enter fullscreen mode Exit fullscreen mode

When you try and test the HomeComponent, there will be errors because you need to include the HelloComponent in the TestBed configuration.

You will have to stub out the nested component and that should look like this:

@Component({ selector: 'app-hello', template: '' })
class HelloStubComponent implements Partial<HelloComponent> {
  @Input() name;
}
Enter fullscreen mode Exit fullscreen mode

Then in the TestBed configuration you will have something like this:

TestBed.configureTestingModule({
  declarations: [
    HomeComponent,
    HelloStubComponent
  ]
}).compileComponents();
Enter fullscreen mode Exit fullscreen mode

To make things more convenient, you can include the definition of the stub component within your component file:

// hello.component.ts
const selector = 'app-hello';
@Component({
  selector,
  // ...
)
export class HelloComponent {
  @Input() name;
}
@Component({ selector, template: '' })
export class HelloStubComponent implements Partial<HelloComponent> {
  @Input() name;
}
Enter fullscreen mode Exit fullscreen mode

When compiling your Angular app, the module will declare HelloComponent. When running your tests, the test bed module configuration will declare HelloStubComponent.

You can use Partial<T>, a utility type from TypeScript to ensure that your stubbed component matches the interface of the actual component class.

By keeping the stub definition close to the actual component class, you can re-use the stub in multiple tests.

Stubs and Stub Providers for Services in Angular

For a service, you can do something similar:

// world-service.ts
@Injectable({ providedIn: 'root' })
export class WorldService {}

export class WorldServiceStub {}
export const worldServiceStubProvider = {
  provide: WorldService,
  useFactory: () => new WorldServiceStub()
}
Enter fullscreen mode Exit fullscreen mode

Then in your tests you can setup the TestBed like this:

import { worldServiceStubProvider } from 'path/to/world-service.ts';
// ...
TestBed.configureTestingModule({
  // ...
  providers: [ worldServiceStubProvider ]
});

// and then you can use the following to get the reference to the stub provider from the TestBed:
TestBed.get(WorldService);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)