Angular supports the decomposition of components by allowing you to include one into another. To test a component that contains other elements you have to declare them in the test configuration. Don’t forget about any @Input
property of an aggregated component or running the test suite will result with the following error:
Template parse errors: Can't bind to property since it isn't a known property of component
Let’s use the following two components from the official Angular documentation.
The first one is the HeroChildComponent
that receives a hero
instance from the parent component and displays it in a header:
// component-interaction/src/app/hero-child.component.ts import { Component, Input } from '@angular/core'; import { Hero } from './hero'; @Component({ selector: 'app-hero-child', template: ` <h3>{{hero.name}} says:</h3> ` }) export class HeroChildComponent { @Input() hero: Hero; }
The second one is the HeroParentComponent
that passes the hero
instance to the <app-hero-child>
element:
// component-interaction/src/app/hero-parent.component.ts import { Component } from '@angular/core'; import { HEROES } from './hero'; @Component({ selector: 'app-hero-parent', template: ` <h2>{{master}} controls {{heroes.length}} heroes</h2> <app-hero-child *ngFor="let hero of heroes" [hero]="hero" </app-hero-child> ` }) export class HeroParentComponent { heroes = HEROES; }
The test for the HeroParentComponent
will succeed if we declare in it the child component – including the property that is passed with @Input
:
// component-interaction/src/app/hero-parent.component.spec.ts … import { Component, Input} from '@angular/core'; import { Hero } from './hero'; @Component({selector: 'app-hero-child', template: ''}) class HeroChildComponent { @Input() hero: Hero; } … declarations: [ HeroParentComponent, HeroChildComponent ] …
The following file contains the full test file for HeroParentComponent
:
// component-interaction/src/app/hero-parent.component.spec.ts import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { Component, Input} from '@angular/core'; import { HeroParentComponent } from './app-hero-parent.component'; import { Hero } from './hero'; @Component({selector: 'app-hero-child', template: ''}) class HeroChildComponent { @Input() hero: Hero; } describe('HeroParentComponent', () => { let component: HeroParentComponent; let fixture: ComponentFixture<HeroParentComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ HeroParentComponent, HeroChildComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(HeroParentComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
Without mocking the hero
property in the child component, the test suite fails with the following error:
HeroChildComponent should create
[object ErrorEvent] thrown
You can simply create the mock for hero
like this:
// component-interaction/src/app/hero-child.component.spec.ts … import { Hero } from './hero'; … beforeEach(() => { … component.hero = {id:1, name: 'hero1'}; …
The following file contains the full test file for HeroChildComponent
:
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { HeroChildComponent } from './app-hero-child.component'; import { Hero } from './hero'; describe('HeroChildComponent', () => { let component: HeroChildComponent; let fixture: ComponentFixture<HeroChildComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ HeroChildComponent ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(HeroChildComponent); component = fixture.componentInstance; component.hero = {id:1, name: 'hero1'}; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
Photo by Daria Shevtsova on StockSnap
Spring Security allows us to use role-based control to restrict access to API resources. However,…
A custom annotation in Spring Boot tests is an easy and flexible way to provide…
Delegating user management to Keycloak allows us to better focus on meeting the business needs…
Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…
Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…
Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…