Mocking child components – multiple components match node with tagname error

I’m currently testing a component (BuilderComponent) with a child (BuilderNavbarComponent). I’d like to mock the child component in my test but keep getting the following error message: Multiple components match node with tagname app-builder-navbar. What’s the best way of fixing this?

describe('BuilderComponent', () => {
  let component: BuilderComponent;
  let store: MockStore;
  let initialState: IBuilder;
  let fixture: ComponentFixture<BuilderComponent>;
  const state = TEST_BUILDER_INITIAL_STATE;
  const reducers: ActionReducerMap<State> = { router: routerReducer };
  const metaReducers: MetaReducer<State>[] = !environment.production ? [logger] : [];

  interface State {
    router: fromRouter.RouterReducerState<BaseRouterStoreState>;
  }

  function logger(reducer: ActionReducer<State>): ActionReducer<State> {
    return (state, action) => {
      const result = reducer(state, action);
      console.groupCollapsed(action.type);
      console.log('prev state', state);
      console.log('action', action);
      console.log('next state', result);
      console.groupEnd();
      return result;
    };
  }

  beforeEach(() => {
    initialState = state;
  });

  @Component({
    selector: 'app-builder-navbar',
    template: '<div></div>',
  })
  class MockBuilderNavbarComponent {}

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [BuilderComponent, MockBuilderNavbarComponent],
      imports: [
        CommonModule,
        ToastrModule.forRoot(),
        ModalModule.forRoot(),
        QuillModule.forRoot(),
        EffectsModule.forRoot(),
        StoreModule.forRoot(reducers, {
          metaReducers,
          runtimeChecks: {
            strictActionImmutability: true,
            strictStateImmutability: true,
          },
        }),
        StoreModule.forFeature('builder', fromBuilder.reducer),
        AngularFirestoreModule,
        AngularFireModule.initializeApp(environment.firebaseConfig),
        ReactiveFormsModule,
        DirectivesModule,
        TooltipModule,
        ModalsModule,
        ShellModule,
        SharedModule,
        BuilderNavbarModule,
        BuilderBodyModule,
        HttpClientModule,
        RouterTestingModule.withRoutes([
          { path: 'preview', component: PreviewComponent },
          { path: 'builder', component: BuilderComponent },
        ]),
      ],
      providers: [
        provideMockStore({ initialState }),
        BuilderService,
        ToastrService,
        BsModalRef,
        UserService,
        QuillService,
      ],
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(BuilderComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  describe('onResize()', () => {
    it('should trigger event when window is resized', () => {
      spyOn(component, 'onResize');
      spyOn(component, 'getViewportSize');
      window.dispatchEvent(new Event('resize'));
      expect(component.onResize).toHaveBeenCalled();
      component.onResize();
      expect(component.getViewportSize).toHaveBeenCalled();
    });
  });

  describe('ngOnInit()', () => {
    it('should retrieve values from store', () => {
      fakeAsync(() => {
        const fixture = TestBed.createComponent(BuilderComponent);
        const componentInstance = fixture.componentInstance;
        fixture.whenStable().then(() => {
          store.setState(initialState);
          expect(componentInstance['courseBuffer']).toBeDefined();
          expect(componentInstance['courseName']).toBeDefined();
          expect(componentInstance['selectedCourseContentElementUid']).toBeNull();
        });
      });
    });
  });

  afterEach(() => {
    initialState = state;
  });
});

Answer

You have created mock child component – MockBuilderNavbarComponent and included it in declarations.

However, you are also importing BuilderNavbarModule which contains BuilderNavbarComponent in its declaration.

Remove the module from imports and it should work.