title: Angular 9 Component Test: Export of name 'ngbNav' not found
body: <p>I have a modal component which I would like to test.
  But it is always complaining about "Export of name 'ngbNav' not found".
  Any ideas would be great on how to solve this.</p>
  
  <pre><code>Error: Export of name 'ngbNav' not found!
          at cacheMatchingLocalNames (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13112:1)
          at resolveDirectives (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:12871:1)
          at elementStartFirstCreatePass (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:21229:1)
          at ɵɵelementStart (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:21271:1)
          at TemplateModalComponent_Template (ng:///TemplateModalComponent.js:381:9)
          at executeTemplate (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:12129:1)
          at renderView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11899:1)
          at renderComponent (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:13509:1)
          at renderChildComponents (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11700:1)
          at renderView (http://localhost:9876/_karma_webpack_/node_modules/@angular/core/__ivy_ngcc__/fesm2015/core.js:11925:1)
  </code></pre>
  
  <p>template-modal.component.html</p>
  
  <pre><code>    &lt;div class="modal-header"&gt;
    &lt;h4 class="modal-title" ngbTooltip="{{template ? template.id : ''}}" triggers="click:blur"&gt;{{"template_edit" | translate}}&lt;/h4&gt;
    &lt;button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')"&gt;
      &lt;span aria-hidden="true"&gt;&amp;times;&lt;/span&gt;
    &lt;/button&gt;
  &lt;/div&gt;
  &lt;div class="modal-body"&gt;
    &lt;form class="form" [formGroup]="this.templateFormGroup"&gt;
      &lt;div formGroupName="template"&gt;
        &lt;div class="row"&gt;
          &lt;div class="col-md-6"&gt;
            &lt;div class="form-group row"&gt;
              &lt;label class="col-sm-3 col-form-label"&gt;Name&lt;/label&gt;
              &lt;div class="col-sm-9"&gt;
                &lt;input type="text" class="form-control" name="name" formControlName="name" required/&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="col-md-6"&gt;
            &lt;div class="form-group row"&gt;
              &lt;label class="col-sm-3 col-form-label"&gt;Instrument Type&lt;/label&gt;
              &lt;div class="col-sm-9"&gt;
                &lt;input type="text" class="form-control" name="instrumentType" formControlName="instrumentType" value="DERIVATIVE" readonly /&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="row" *ngIf="isStandardTemplate"&gt;
          &lt;div class="col-md-6"&gt;
            &lt;div class="form-group row"&gt;
              &lt;label class="col-sm-3 col-form-label"&gt;Publisher&lt;/label&gt;
              &lt;div class="col-sm-9"&gt;
                &lt;select class="form-control" formControlName="publisherId" (change)="resetAdvertiser()"&gt;
                  &lt;option [value]="null"&gt;{{"select-choose" | translate}}&lt;/option&gt;
                  &lt;option [value]="p.id" *ngFor="let p of publisher | orderBy:'name'"&gt;{{p.name}}&lt;/option&gt;
                &lt;/select&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="col-md-6"&gt;
            &lt;div class="form-group row"&gt;
              &lt;label class="col-sm-3 col-form-label"&gt;Advertiser&lt;/label&gt;
              &lt;div class="col-sm-9"&gt;
                &lt;select class="form-control" formControlName="advertiserId" (change)="resetPublisher()"&gt;
                  &lt;option [value]="null"&gt;{{"select-choose" | translate}}&lt;/option&gt;
                  &lt;option [value]="a.id" *ngFor="let a of advertiser | orderBy:'name'"&gt;{{a.name}}&lt;/option&gt;
                &lt;/select&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="row justify-content-end mb-3" *ngIf="!isStandardTemplate"&gt;
          &lt;div class="col-3"&gt;
            &lt;button class="btn btn-secondary form-control" (click)="createStandardTemplateModal()"&gt;Standard Templates&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs justify-content-center"&gt;
          &lt;li [ngbNavItem]="1"&gt;
            &lt;a ngbNavLink&gt;Filter&lt;/a&gt;
            &lt;ng-template ngbNavContent&gt;
              &lt;ngb-alert type="secondary" *ngIf="!filter || filter.length == 0"&gt;Keine Filter vorhanden. Bitte anlegen!
              &lt;/ngb-alert&gt;
              &lt;div class="table-responsive" *ngIf="filter.length &gt; 0"&gt;
                &lt;table class="table"&gt;
                  &lt;thead&gt;
                  &lt;tr&gt;
                    &lt;th&gt;Name&lt;/th&gt;
                    &lt;th&gt;Variable&lt;/th&gt;
                    &lt;th&gt;{{"criteria" | translate}}&lt;/th&gt;
                    &lt;th&gt;{{"comment" | translate}}&lt;/th&gt;
                    &lt;th&gt;&lt;/th&gt;
                  &lt;/tr&gt;
                  &lt;/thead&gt;
                  &lt;tbody&gt;
                  &lt;tr *ngFor="let f of filter | orderBy:'name'"&gt;
                    &lt;td&gt;{{f.name}}&lt;/td&gt;
                    &lt;td&gt;{{f.templateVariableName}}&lt;/td&gt;
                    &lt;td&gt;&lt;span class="badge badge-pill badge-secondary mr-1" *ngFor="let i of f.filterCriteria"&gt;
                        {{i.field}}
                        &lt;/span&gt;&lt;/td&gt;
                    &lt;td&gt;{{f.comment}}&lt;/td&gt;
                    &lt;td&gt;
                      &lt;span class="prodo-icon prodo-delete-icon cursor-pointer float-right" (click)="deleteFilter(f.id)" ngbTooltip="{{'delete' | translate}}"&gt;&lt;/span&gt;
                      &lt;span class="prodo-icon prodo-edit-icon cursor-pointer float-right" *ngIf="f.id" ngbTooltip="{{'edit' | translate}}" (click)="chooseFilter(f.id)"&gt;&lt;/span&gt;
  
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;/tbody&gt;
                &lt;/table&gt;
              &lt;/div&gt;
              &lt;div class="row"&gt;
                &lt;div class="col"&gt;
                  &lt;button type="button" class="btn btn-secondary"
                          (click)="newFilter()"&gt;{{"filter_new" | translate}}&lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/ng-template&gt;
          &lt;/li&gt;
          &lt;li [ngbNavItem]="2"&gt;
            &lt;a ngbNavLink&gt;HTML-Template&lt;/a&gt;
            &lt;ng-template ngbNavContent&gt;
              &lt;div class="row"&gt;
                &lt;div class="col-md-12"&gt;
                  &lt;editor formControlName="html" required name="html" [init]="tinyMceConfig"&gt;&lt;/editor&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/ng-template&gt;
          &lt;/li&gt;
          &lt;li [ngbNavItem]="3"&gt;
            &lt;a ngbNavLink&gt;{{"disclaimer_page_end" | translate}}&lt;/a&gt;
            &lt;ng-template ngbNavContent&gt;
              &lt;div class="row"&gt;
                &lt;div class="col-md-12"&gt;
                  &lt;editor formControlName="disclaimer" name="disclaimer" [init]="tinyMceConfig"&gt;
                  &lt;/editor&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/ng-template&gt;
          &lt;/li&gt;
          &lt;li [ngbNavItem]="4"&gt;
            &lt;a ngbNavLink&gt;{{"disclaimer_at_ad" | translate}}&lt;/a&gt;
            &lt;ng-template ngbNavContent&gt;
              &lt;div class="row"&gt;
                &lt;div class="col-md-12"&gt;
                  &lt;editor formControlName="disclaimerJson" name="disclaimerJson" [init]="tinyMceConfig"&gt;
                  &lt;/editor&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/ng-template&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/div&gt;
    &lt;/form&gt;
    &lt;div [ngbNavOutlet]="nav" class="mt-2"&gt;&lt;/div&gt;
  
  &lt;/div&gt;
  &lt;div class="modal-footer"&gt;
    &lt;button type="button" class="btn btn-light" (click)="activeModal.dismiss()"&gt;Close&lt;/button&gt;
    &lt;button type="button" class="btn btn-success" (click)="passBack()" [disabled]="!templateFormGroup.valid"&gt;Speichern
    &lt;/button&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>template-modal.component.ts</p>
  
  <pre><code>import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
  import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap';
  import {FormBuilder, FormControl, FormGroup} from "@angular/forms";
  import {StandardTemplateModalComponent} from "./standard-template-modal/standard-template-modal.component";
  import {FilterModalComponent} from "./filter-modal/filter-modal.component";
  import {Filter} from "../../../model/filter.model";
  import {Publisher} from "../../../model/publisher.model";
  import {Advertiser} from "../../../model/advertiser.model";
  import {Template} from "../../../model/template.model";
  import {PublisherService} from "../../../services/publisher.service";
  import {AdvertiserService} from "../../../services/advertiser.service";
  import {FilterService} from "../../../services/filter.service";
  import {TemplateService} from "../../../services/template.service";
  import {InstrumentAttributeService} from "../../../services/instrument-attribute.service";
  import {StandardTemplate} from "../../../model/standard-template.model";
  
  @Component({
    selector: 'app-template-modal',
    templateUrl: './template-modal.component.html',
    styleUrls: ['./template-modal.component.scss']
  })
  export class TemplateModalComponent implements OnInit {
  
    @Input()
    public template;
    @Input()
    advertisementId: string;
    @Input()
    isStandardTemplate: boolean;
  
    filter: Filter[] = [];
    publisher: Publisher[];
    advertiser: Advertiser[];
    standardTemplates: Template[];
    templateFormGroup: FormGroup;
    usedInstrumentTypesInFilter: string[];
    fieldsOfInstrumentType: any[] = new Array&lt;string&gt;();
    tinyMceConfig: any;
  
    @Output() passEntry: EventEmitter&lt;any&gt; = new EventEmitter();
    active = 1;
  
  
    constructor(
      public activeModal: NgbActiveModal,
      public publisherService: PublisherService,
      public advertiserService: AdvertiserService,
      private filterService: FilterService,
      private templateService: TemplateService,
      private instrumentAttributeService: InstrumentAttributeService,
      private fb: FormBuilder,
      private modalService: NgbModal) {
    }
  
    ngOnInit() {
      this.loadData();
      this.configureTinyMce();
    }
  
    createFormGroup() {
      return this.fb.group({
          template: this.fb.group(this.template),
          standardTemplate: new FormControl('')
        }
      );
    }
  
    loadData() {
      this.publisherService.get().subscribe((data: Publisher[]) =&gt; { this.publisher = data; });
      this.advertiserService.get().subscribe((data: Advertiser[]) =&gt; { this.advertiser = data; });
      if (!this.isStandardTemplate) {
        this.templateService.getSuitableStandardTemplates(this.advertisementId)
          .subscribe( data =&gt; {
            this.standardTemplates = data;
          });
      }
      this.templateFormGroup = this.createFormGroup();
      this.filterService.get(this.template.id)
        .subscribe( data =&gt; {
  
          this.filter = data;
          this.usedInstrumentTypesInFilter = this.filter.map( f =&gt; f.zertartId).filter((el, i, a) =&gt; i === a.indexOf(el));
  
          for ( const instrumentType of this.usedInstrumentTypesInFilter) {
            this.filterService.getFilterCriteria(instrumentType).subscribe( fields =&gt; {
              this.fieldsOfInstrumentType[instrumentType] = fields;
            });
          }
        });
    }
  
    createStandardTemplateModal() {
      const modalRef = this.modalService.open(StandardTemplateModalComponent, { centered: true, size: 'lg' });
      modalRef.componentInstance.advertisementId = this.advertisementId;
      modalRef.result.then((result: StandardTemplate) =&gt; {
        if (result) {
          // Updating form with values from Standard Template
          this.templateFormGroup.get("template").patchValue(result);
          // Result Object for saving
          const template = this.createTemplateResult();
          this.templateService.putTemplate(this.advertisementId, template).subscribe( t =&gt; {
            // Template is saved, now fetch all filter and add them to the template
            this.filterService.get(result.id).subscribe( data =&gt; {
              for (const f of data) {
                // setting the new template id of the filter and remove its id, as it will receive a new one
                f.abstractTemplateId = t.id;
                f.id = null;
                this.filterService.post(f).subscribe( _ =&gt; this.activeModal.close() );
              }
            });
          });
        }
      });
    }
  
    newFilter() {
      const modalRef = this.modalService.open(FilterModalComponent, { centered: true, size: 'xl' });
      modalRef.componentInstance._templateId = this.template.id;
      modalRef.result.then((result: Filter) =&gt; {
        if (result) {
          this.filterService.post(result).subscribe(_ =&gt; {
            this.loadData();
          });
        }
      });
    }
  
    deleteFilter(filterId: string) {
      this.filterService.delete(filterId).subscribe( _ =&gt; {
        this.loadData();
      });
    }
  
    chooseFilter(filterId: string) {
      const modalRef = this.modalService.open(FilterModalComponent, { centered: true, size: 'xl' });
      modalRef.componentInstance.filterId = filterId;
      modalRef.result.then((result: Filter) =&gt; {
        if (result) {
          this.filterService.put(filterId, result).subscribe(_ =&gt; {
            this.loadData();
          });
        }
      });
    }
  
    configureTinyMce() {
      const that = this;
  
      this.tinyMceConfig = {
        menubar: false,
        branding: false,
        height: 300,
        base_url: '/tinymce',
        suffix: '.min',
        inline: false,
        valid_elements: '*[*]',
        plugins: [
          'advlist lists link image directionality',
          'searchreplace visualblocks visualchars media table paste pagebreak code'
        ],
        toolbar: 'filterbutton filterIterationButton | undo redo formatselect table | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat hr pagebreak code',
        table_resize_bars: false,
        setup: function (editor) {
          const test = that.filter.map(f =&gt; {
            if ( f.maximumNumberOfResults &lt;= 1) {
              return {
                type: 'nestedmenuitem',
                text: f.templateVariableName,
                icon: 'template',
                getSubmenuItems: function () {
                  return f.allowedFields.map(field =&gt; {
                    return {
                      type: 'menuitem',
                      text: field,
                      icon: 'paste-text',
                      onAction: function () {
                        editor.insertContent(
                          '&lt;span th:text="${' + f.templateVariableName + '.' + field + '}"&gt;' + f.templateVariableName + '.' + field + '&lt;/span&gt;'
                        );
                      }
                    };
                  });
                }
              };
            } else {
              return [];
            }
          });
          const filterIteration = that.filter.map(f =&gt; {
            if (f.maximumNumberOfResults &gt; 1) {
              return {
                type: 'nestedmenuitem',
                text: f.templateVariableName,
                icon: 'template',
                getSubmenuItems: function() {
                  const filterWithMultipleResults = (element: Filter) =&gt; element.maximumNumberOfResults &gt; 1;
                  if ( that.filter.some(filterWithMultipleResults) ) {
                    return f.allowedFields.map( field =&gt; { return {
                      type: 'menuitem',
                      text: field,
                      icon: 'paste-text',
                      onAction: function () {
                        const iteration =
                          '&lt;table&gt;' +
                          '&lt;tr th:each="item: ${' + f.templateVariableName + '}"&gt;' +
                          '&lt;td th:text="${item.' + field + '}" /&gt;' +
                          '&lt;/tr&gt;' +
                          '&lt;/table&gt;';
                        console.log("inserting:");
                        console.log(iteration);
                        editor.insertContent(iteration);
  
                      }
                    }; });
                  } else {
                    return [];
                  }
  
                }
              };
            } else {
              return [];
            }
  
          });
          /* example, adding a toolbar menu button */
          editor.ui.registry.addMenuButton('filterbutton', {
            text: 'Filter',
            fetch: function (callback) {
              callback(test);
            }
          });
          editor.ui.registry.addMenuButton('filterIterationButton', {
            text: 'Filter Iteration',
            fetch: function (callback) {
              callback(filterIteration);
            }
          });
        },
        image_advtab: true,
        imagetools_toolbar: 'rotateleft rotateright | flipv fliph | editimage imageoptions',
        paste_data_images: !0,
        importcss_append: !0,
        images_upload_handler: function (e, t, a) {
          t('data:' + e.blob().type + ';base64,' + e.base64());
        },
      };
    }
  
    resetAdvertiser() {
      this.templateFormGroup.get("template").get("advertiserId").reset();
    }
  
    resetPublisher() {
      this.templateFormGroup.get("template").get("publisherId").reset();
    }
  
    createTemplateResult() {
      let result;
      if (this.isStandardTemplate) {
        result =  Object.assign({}, this.templateFormGroup.get('template').value) as StandardTemplate;
      } else {
        result =  Object.assign({}, this.templateFormGroup.get('template').value) as Template;
      }
      result = Object.assign({}, result);
      return result;
    }
  
    passBack() {
      const result = this.createTemplateResult();
      this.activeModal.close(result);
    }
  
  }
  </code></pre>
  
  <p>In my test file I am going this way:</p>
  
  <pre><code>import {async, TestBed} from '@angular/core/testing';
  
  import {TemplateModalComponent} from './template-modal.component';
  import {HttpClient} from "@angular/common/http";
  import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
  import {RouterTestingModule} from "@angular/router/testing";
  import {TranslateLoader, TranslateModule} from "@ngx-translate/core";
  import {HttpLoaderFactory} from "../../../app.module";
  import {FormBuilder, FormsModule, NgForm} from "@angular/forms";
  import {NgbActiveModal, NgbModal, NgbNav, NgbNavConfig} from "@ng-bootstrap/ng-bootstrap";
  import {AdslotService} from "../../../services/adslot.service";
  import {ErrorHandlingService} from "../../../services/error-handling.service";
  import {ToastService} from "../../../services/toast.service";
  
  describe('TemplateModalComponent', () =&gt; {
    let httpClient: HttpClient;
    let httpTestingController: HttpTestingController;
  
    beforeEach(async(() =&gt; {
      TestBed.configureTestingModule({
        imports: [
          HttpClientTestingModule,
          TranslateModule.forRoot({
            loader: {
              provide: TranslateLoader,
              useFactory: HttpLoaderFactory,
              deps: [HttpClient]
            }
          }),
        ],
        declarations: [ TemplateModalComponent ],
        providers: [
          FormsModule,
          NgbActiveModal,
          AdslotService,
          ErrorHandlingService,
          ToastService,
          FormBuilder,
        ]
      }).compileComponents();
      // Inject the http service and test controller for each test
      httpClient = TestBed.get(HttpClient);
      httpTestingController = TestBed.get(HttpTestingController);
  
    }));
  
    it('should create the app', () =&gt; {
      const fixture = TestBed.createComponent(TemplateModalComponent);
      const app = fixture.debugElement.componentInstance;
      expect(app).toBeTruthy();
    });
  });
  </code></pre>
  
  <p>I really appreciate any hints or helping steps to debug this.
  Cheers Maik</p>