title: Why are two mock child component instances created while running Angular unit tests?
body: <p>My Angular 13 application has the following:</p>
  <ul>
  <li>An app component that displays a welcome message and a parent component</li>
  <li>A parent component that displays some text and a child component inside a <code>div</code> and listens to the child component's selection changes, using <code>@ViewChild</code> to get the child component</li>
  <li>A child component that displays a <code>mat-select</code> and emits the user's selections via a private <code>EventEmitter</code> that is exposed through a public <code>Observable</code> output.</li>
  </ul>
  <p><strong>When I run the app</strong>, everything works. When I make a selection in the child component, the parent component gets the selection change as expected. But <strong>when I run my parent component unit tests</strong>, using a mock child component that has an RxJs <code>ReplaySubject</code> in place of the <code>EventEmitter</code> and <code>Observable</code>, the parent component does <em>not</em> get the expected selection change.</p>
  <p>While investigating this behavior, I added some <code>console.log</code> statements and some unique object IDs to find out which components were getting created. I learned that one parent component instance is created, as expected, but <em>two different</em> mock child component instances are created! Worse, one of the child component instances is set as the parent component's <code>ViewChild</code> and available in <code>ngAfterViewInit</code>, but the other child component instance is returned in the parent test when querying <code>component.debugElement</code>. That means that when I artificially emit a selection change on the test's child component, the parent never sees it.</p>
  <p>Look in the test output below and see that two mock child components are created. The test gets the component with ID 1 by querying the <code>debugElement</code>, but the parent component gets the component with ID 2 as its <code>ViewChild</code>. I only want there to be one mock child component.</p>
  <p>Again, this is only a problem during unit testing. In the running app, only one child component instance is created, and everything works fine.</p>
  <p>Why is Angular creating two mock child component instances during testing, and how can I force it to create just one?</p>
  <p><code>app.module.ts</code>:</p>
  <pre><code>import { NgModule } from '@angular/core';
  import { FormsModule } from '@angular/forms';
  import { MatSelectModule } from '@angular/material/select';
  import { BrowserModule } from '@angular/platform-browser';
  import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
  import { AppComponent } from './app.component';
  import { ChildComponent } from './child/child.component';
  import { ParentComponent } from './parent/parent.component';
  
  @NgModule({
    declarations: [
      AppComponent,
      ParentComponent,
      ChildComponent
    ],
    imports: [
      BrowserAnimationsModule,
      BrowserModule,
      FormsModule,
      MatSelectModule
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  </code></pre>
  <p><code>app.component.html</code>:</p>
  <pre><code>&lt;h1&gt;Welcome&lt;/h1&gt;
  
  &lt;app-parent&gt;&lt;/app-parent&gt;
  </code></pre>
  <p><code>app.component.ts</code>:</p>
  <pre><code>import { Component } from '@angular/core';
  
  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
  })
  export class AppComponent {
    title = 'parent-child-test';
  }
  </code></pre>
  <p><code>parent.component.html</code>:</p>
  <pre><code>&lt;div class=&quot;order-form&quot;&gt;
      &lt;h2&gt;Order Form&lt;/h2&gt;
      &lt;div&gt;
          &lt;b&gt;Flavor&lt;/b&gt;
          &lt;app-child&gt;&lt;/app-child&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  <p><code>parent.component.ts</code>:</p>
  <pre><code>import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
  import { ChildComponent, Flavor, flavors } from '../child/child.component';
  
  @Component({
    selector: 'app-parent',
    templateUrl: './parent.component.html',
    styleUrls: ['./parent.component.scss']
  })
  export class ParentComponent implements AfterViewInit {
  
    private static lastId = 0;// For testing
  
    readonly id: number;
  
    flavor: Flavor = flavors[0];
  
    @ViewChild(ChildComponent)
    private childComponent!: ChildComponent;
  
    constructor() {
      this.id = ++ParentComponent.lastId;
      console.log(`Created ${this.constructor.name} ${this.id}`);
    }
  
    ngAfterViewInit(): void {
      console.log(
        `In parent afterViewInit, child component ID is ${this.childComponent.id}`
      );
      this.childComponent.flavorChanged.subscribe(flavor =&gt; {
        console.log(`New flavor is ${flavor}. Everything seems to be working!`);
        this.flavor = flavor;
      });
    }
  
  }
  </code></pre>
  <p><code>parent.component.spec.ts</code>:</p>
  <pre><code>import { Component } from '@angular/core';
  import { ComponentFixture, TestBed } from '@angular/core/testing';
  import { By } from '@angular/platform-browser';
  import { ReplaySubject } from 'rxjs';
  import { ChildComponent, Flavor, flavors } from '../child/child.component';
  import { ParentComponent } from './parent.component';
  
  @Component({
    selector: 'app-child',
    template: '',
    providers: [
      { provide: ChildComponent, useClass: MockChildComponent }
    ]
  })
  class MockChildComponent {
  
    private static lastId = 0;// For testing
  
    readonly id: number;// For testing
  
    readonly flavorChanged = new ReplaySubject&lt;Flavor&gt;(1);
  
    constructor() {
      this.id = ++MockChildComponent.lastId;// For testing
      console.log(`Created ${this.constructor.name} ${this.id}`);
    }
  
  }
  
  describe('ParentComponent', () =&gt; {
    let component: ParentComponent;
    let fixture: ComponentFixture&lt;ParentComponent&gt;;
  
    beforeEach(async () =&gt; {
      await TestBed.configureTestingModule({
        declarations: [MockChildComponent, ParentComponent]
      }).compileComponents();
    });
  
    beforeEach(() =&gt; {
      fixture = TestBed.createComponent(ParentComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    });
  
    it('should receive flavor when child component emits it', () =&gt; {
      let flavor: Flavor = flavors[0];
  
      expect(fixture.componentInstance.flavor).toEqual(flavor);
  
      flavor = flavors[flavors.length - 1];
  
      // I tried queryAll instead of query to see if I could get
      // more than one, but it only returned one, and this is it:
      const childComponent: MockChildComponent = fixture.debugElement.query(
        By.directive(ChildComponent)
      ).componentInstance;
      console.log(`In test, child component ID is ${childComponent.id}`);
      childComponent.flavorChanged.next(flavor);
  
      expect(fixture.componentInstance.flavor).toEqual(flavor);
    });
  });
  </code></pre>
  <p><code>child.component.html</code>:</p>
  <pre><code>&lt;mat-select [(ngModel)]=&quot;flavor&quot;&gt;
      &lt;mat-option *ngFor=&quot;let flavorOption of flavors&quot; [value]=&quot;flavorOption&quot;&gt;
          {{ flavorOption }}
      &lt;/mat-option&gt;
  &lt;/mat-select&gt;
  </code></pre>
  <p><code>child.component.ts</code>:</p>
  <pre><code>import { Component, EventEmitter, OnInit, Output } from '@angular/core';
  
  export const flavors = ['Chocolate', 'Strawberry', 'Vanilla'] as const;
  export type Flavor = typeof flavors[number];
  
  @Component({
    selector: 'app-child',
    templateUrl: './child.component.html',
    styleUrls: ['./child.component.scss']
  })
  export class ChildComponent {
  
    private static lastId = 0;// For testing
  
    readonly id: number;// For testing
  
    readonly flavors = flavors;
  
    selectedFlavor: Flavor = flavors[0];
  
    private readonly flavorChangedEmitter = new EventEmitter&lt;Flavor&gt;();
  
    @Output()
    readonly flavorChanged = this.flavorChangedEmitter.asObservable();
  
    constructor() {
      this.id = ++ChildComponent.lastId;// For testing
      console.log(`Created ${this.constructor.name} ${this.id}`);
    }
  
    get flavor(): Flavor {
      return this.selectedFlavor as Flavor;
    }
  
    set flavor(newFlavor: Flavor) {
      this.selectedFlavor = newFlavor;
  
      this.flavorChangedEmitter.emit(newFlavor);
    }
  
  }
  </code></pre>
  <p>Console messages when running the application and choosing a flavor (this is fine):</p>
  <pre><code>parent.component.ts:22 Created ParentComponent 1
  child.component.ts:28 Created ChildComponent 1
  parent.component.ts:26 In parent afterViewInit, child component ID is 1
  parent.component.ts:28 New flavor is Vanilla. Everything seems to be working!
  </code></pre>
  <p>Test output (this doesn't work):</p>
  <pre><code>LOG: 'Created ParentComponent 1'
  LOG: 'Created MockChildComponent 1'
  LOG: 'Created MockChildComponent 2'
  LOG: 'In parent afterViewInit, child component ID is 2'
  LOG: 'In test, child component ID is 1'
  Chrome 100.0.4896.75 (Windows 10) ParentComponent should receive flavor when child component emits it FAILED
          Error: Expected 'Chocolate' to equal 'Vanilla'.
              at &lt;Jasmine&gt;
              at UserContext.&lt;anonymous&gt; (src/app/parent/parent.component.spec.ts:61:46)        
              at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:1)
              at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:1)   
  Chrome 100.0.4896.75 (Windows 10): Executed 1 of 5 (1 FAILED) (skipped 4) (0.117 secs / 0.08 secs)
  TOTAL: 1 FAILED, 0 SUCCESS
  </code></pre>