title: Jasmin : How to mock @ViewChild component in Angular 8
body: <p>i'm trying to test a component with child components which are also stored as <code>@ViewChild</code></p>
  
  <p><strong>project-estimation.component.ts</strong></p>
  
  <pre><code>import { Component, OnInit, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
  import { ProjectCreateComponent } from './project-create/project-create.component';
  import { ProjectCaracComponent } from './project-carac/project-carac.component';
  import { Subscription } from 'rxjs';
  
  @Component({
    selector: 'app-project-estimation',
    templateUrl: './project-estimation.component.html',
    styleUrls: ['./project-estimation.component.css']
  })
  export class ProjectEstimationComponent implements OnInit, AfterViewInit, OnDestroy {
  
    @ViewChild(ProjectCreateComponent, {static: false}) createComp: ProjectCreateComponent;
    @ViewChild(ProjectCaracComponent, {static: false}) caracComp: ProjectCaracComponent;
  
    public isCreateStepCompleted = false;
    public isCaracStepCompleted = false;
    private subTokens: Subscription[] = [];
  
    constructor() { }
  
    public ngOnInit() {
    }
  
    public ngAfterViewInit(): void {
  
      this.subTokens.push(this.createComp.projectTypeForm.statusChanges
        .subscribe((status) =&gt; {
        this.isCreateStepCompleted = this.isFormStatusValid(status);
      }));
  
      this.subTokens.push(this.caracComp.projectCaracForm.statusChanges
        .subscribe((status) =&gt; {
        this.isCaracStepCompleted = this.isFormStatusValid(status);
      }));
    }
  
    public ngOnDestroy(): void {
      for (const token of this.subTokens) {
        token.unsubscribe();
      }
    }
  
    public isFormStatusValid(status: string) {
      return status === 'VALID';
    }
  }
  
  </code></pre>
  
  <p><strong>project-estimation.component.html</strong></p>
  
  <pre><code>&lt;mat-card&gt;
    &lt;mat-card-title&gt;
      &lt;p&gt;Estimation de projet&lt;/p&gt;
    &lt;/mat-card-title&gt;
  
    &lt;mat-card-content&gt;
      &lt;mat-horizontal-stepper linear #stepper&gt;
          &lt;mat-step id="createStep" [completed]="isCreateStepCompleted"&gt;
            &lt;ng-template matStepLabel&gt;Créez votre projet&lt;/ng-template&gt;
            &lt;app-project-create&gt;&lt;/app-project-create&gt;
          &lt;/mat-step&gt;
          &lt;mat-step id="caracStep" [completed]="isCharacStepCompleted"&gt;
            &lt;ng-template matStepLabel&gt;Définissez les characteristiques&lt;/ng-template&gt;
            &lt;app-project-charac&gt;&lt;/app-project-charac&gt;
          &lt;/mat-step&gt;
          &lt;mat-step id="quotationStep" [completed]="isQuotationStepCompleted"&gt;
            &lt;ng-template matStepLabel&gt;Récupérez votre estimation&lt;/ng-template&gt;
            &lt;app-project-quotation&gt;&lt;/app-project-quotation&gt;
          &lt;/mat-step&gt;
      &lt;/mat-horizontal-stepper&gt;
    &lt;/mat-card-content&gt;
  &lt;/mat-card&gt;
  </code></pre>
  
  <p>Now i want to set a non regression test to be sure that if one of the child component emits statusChanges, the status is correctly updated.</p>
  
  <p>Here is the test i tried to set up</p>
  
  <p><strong>project-estimation.components.spect.ts</strong></p>
  
  <pre><code>class FormGroupMock {
  
    public status: string;
    public statusChanges: BehaviorSubject&lt;string&gt;;
  
    public constructor() {
  
      this.status = 'VALID';
      this.statusChanges = new BehaviorSubject(this.status);
    }
  
    public setStatus(status: string): void {
      this.status = status;
      this.statusChanges.next(this.status);
    }
  }
  
  @Component({
    selector: 'app-project-create',
    template: ''
  })
  class CreateCompMockComponent {
    public projectTypeForm = new FormGroupMock();
  }
  
  @Component({
    selector: 'app-project-carac',
    template: ''
  })
  class CaracCompMockDComponent {
    public projectCaracForm = new FormGroupMock();
  }
  
  describe('ProjectEstimationComponent', () =&gt; {
    let component: ProjectEstimationComponent;
    let fixture: ComponentFixture&lt;ProjectEstimationComponent&gt;;
  
    beforeEach(async(() =&gt; {
      TestBed.configureTestingModule({
        imports: [
          MaterialModule,
          RouterTestingModule.withRoutes(testProjectEstimationRoutes),
          ReactiveFormsModule,
          BrowserAnimationsModule
        ],
        declarations: [
          DummyComponent,
          CreateCompMockComponent,
          CaracCompMockDComponent,
          ProjectEstimationComponent,
        ],
        providers: [
        ]
      })
      .compileComponents().then(() =&gt; {
        fixture = TestBed.createComponent(ProjectEstimationComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    }));
  
    it('should be created', () =&gt; {
      expect(component).toBeTruthy();
    });
  }
  </code></pre>
  
  <p>However when i run this test i get : </p>
  
  <pre><code>Failed: Uncaught (in promise): TypeError: Cannot read property 'projectTypeForm' of undefined
  TypeError: Cannot read property 'projectTypeForm' of undefined
      at ProjectEstimationComponent.ngAfterViewInit (http://localhost:9876/_karma_webpack_/src/app/project-estimation/project-estimation.component.ts:32:41)
  ...
  </code></pre>
  
  <p>So as you can see, the mock components are not used as ViewChild for the main component.
  <strong>How can i fix this so i can use those mock components</strong> in order to write more complex test like this :</p>
  
  <pre><code>it('should listen for sub component changes', () =&gt; {
      const createComp: CreateCompMockComponent = TestBed.get(ProjectCreateComponent);
      const caracComp: CaracCompMockDComponent = TestBed.get(ProjectCaracComponent);
  
      expect(component.isCreateStepCompleted).toBe(true);
      expect(component.isCaracStepCompleted).toBe(true);
  
      createComp.projectTypeForm.setStatus('INVALID');
      caracComp.projectCaracForm.setStatus('INVALID');
  
      fixture.detectChanges();
  
      expect(component.isCreateStepCompleted).toBe(false);
      expect(component.isCaracStepCompleted).toBe(false);
    });
  </code></pre>