2017-02-09 2 views
0

Ich erstelle einen Test für eine Komponente namens "DashboardComponent". Die Testspezifikation ist schwer zu erstellen. Karma wirft den Fehler "Unerwarteter Wert 'DecoratorFactory', der vom Modul 'DynamicTestModule' importiert wurde".Benötigen Sie Unterstützung bei der Angular2 TestBed-Konfiguration? DecoratorFactory-Fehler

Ich habe versucht, Code zu entfernen, bis der Fehler verschwindet und dann Code zurück, bis es wieder erscheint, um die Quelle zu identifizieren. Dies hat jedoch nicht zu fruchtbaren Ergebnissen geführt, da der Code bei Verwendung mehrerer verschiedener Konfigurationen bricht und ich nicht feststellen kann, durch welche Konfiguration der Fehler auftritt und welcher Fehler ausgelöst wird. Ich vermute, dass die schlechte Konfiguration in all meinen nicht fehlgeschlagenen Versuchen existiert, und bestimmte Codezeilen, wie die Hinzufügung eines it() Aufrufs, bewirken, dass der Fehler plötzlich sichtbar wird, wenn er vorher nicht sichtbar war.

Es ist meine Hoffnung, dass jemand mit mehr Erfahrung als ich meinen Fehler sehen und einen Rat geben wird. Andere hatten dasselbe Problem mit StackOverflow, und die Lösungen, die für sie funktionierten, scheinen in dieser Situation nicht zu gelten.

Code-Diagramm

Um die Code-Basis leichter zu verdauen zu machen, ich habe ein UML-Diagramm erstellt, um die Abhängigkeiten zu zeigen, dass ich in der TestBed Konfiguration zu replizieren versuchen.

enter image description here

Das grüne Element ist das Element, getestet. Die Paketelemente werden in das Modul importiert, und die Dienste haben jeweils eine Scheinklasse, und an ihrer Stelle stellen wir die Scheinklassen bereit. Wir müssen drei Komponenten deklarieren, da die Vorlage von DashboardComponent auf PatientListComponent verweist und die Vorlage von PatientListComponent auf PatientListItemComponent basiert.

-Code & Dateien

Es ist meine Hoffnung, keinen Roman in dieser Frage zu schreiben, also werde ich mehr Dateien & Code hinzufügen, wenn sie angefordert werden. Bis zur Anforderung werden die Dateien bereitgestellt, die für die Identifizierung des Problems am relevantesten erscheinen.

app/Armaturenbrett/dashboard.component.spec.ts

import { DebugElement, NgModule } from '@angular/core'; 
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 
import { FormsModule }    from '@angular/forms'; 
import { By }      from '@angular/platform-browser'; 
import { Router, RouterModule }  from '@angular/router'; 

import { DashboardComponent }  from './dashboard.component'; 
import { PatientListComponent }  from '../patient-list/patient-list.component'; 
import { PatientListItemComponent } from '../patient-list-item/patient-list-item.component'; 
import { AuthenticationService }  from '../authentication.service'; 
import { PatientSummaryService }  from '../patient-summary/patient-summary.service'; 

import { MockAuthService, MockPatientSummaryService, RouterStub } from './dashboard.mocks'; 

/* 
* DebugElement and By are currently not used. I have left them in the import statements above, 
* because any test suite WILL use them when it is fully developed. 
*/ 
describe("DashboardComponent",()=>{ 
    var component : DashboardComponent     = null; 
    var fixture : ComponentFixture<DashboardComponent> = null; 
    beforeEach( 
     async( 
      ()=>{ 
       TestBed.configureTestingModule(
        { 
        imports: [ NgModule, RouterModule, FormsModule ], 
        declarations: [ DashboardComponent, PatientListComponent, PatientListItemComponent ], 
        providers: [ 
         { provide: AuthenticationService, useClass: MockAuthService }, 
         { provide: PatientSummaryService, useClass: MockPatientSummaryService }, 
         { provide: Router, useClass: RouterStub } 
           ] 
        } 
       ).compileComponents(); 
    })); 
    beforeEach(()=>{ 
     fixture = TestBed.createComponent(DashboardComponent); 
    }); 
    it("has a test",()=>{ expect(1).toBe(1);}); 
    /* 
    describe("filter section behavior",()=>{}); 
    describe("list display behavior", async(()=>{ 
     describe("filtered-list behavior", async(()=>{ 
      //component.filterList = true; 
      fixture.detectChanges(); 
      fixture.whenStable().then((done:any)=>{ 
       debugger; 
      }); 
     })); 
     describe("unfiltered-list behavior",()=>{ 
      //component.filterList = false; 
     }); 
    })); 
    */ 
}); 

app/Armaturenbrett/dashboard.mocks.ts

import { DebugElement, NgModule } from '@angular/core'; 
import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 
import { FormsModule }    from '@angular/forms'; 
import { By }      from '@angular/platform-browser'; 
import { Router, RouterModule }  from '@angular/router'; 

import { DashboardComponent }  from './dashboard.component'; 
import { PatientListComponent }  from '../patient-list/patient-list.component'; 
import { PatientListItemComponent } from '../patient-list-item/patient-list-item.component'; 
import { AuthenticationService }  from '../authentication.service'; 
import { PatientSummaryService }  from '../patient-summary/patient-summary.service'; 

import { MockAuthService, MockPatientSummaryService, RouterStub } from './dashboard.mocks'; 

/* 
* DebugElement and By are currently not used. I have left them in the import statements above, 
* because any test suite WILL use them when it is fully developed. 
*/ 
describe("DashboardComponent",()=>{ 
    var component : DashboardComponent     = null; 
    var fixture : ComponentFixture<DashboardComponent> = null; 
    beforeEach( 
     async( 
      ()=>{ 
       TestBed.configureTestingModule(
        { 
        imports: [ NgModule, RouterModule, FormsModule ], 
        declarations: [ DashboardComponent, PatientListComponent, PatientListItemComponent ], 
        providers: [ 
         { provide: AuthenticationService, useClass: MockAuthService }, 
         { provide: PatientSummaryService, useClass: MockPatientSummaryService }, 
         { provide: Router, useClass: RouterStub } 
           ] 
        } 
       ).compileComponents(); 
    })); 
    beforeEach(()=>{ 
     fixture = TestBed.createComponent(DashboardComponent); 
    }); 
    it("has a test",()=>{ expect(1).toBe(1);}); 
    /* 
    describe("filter section behavior",()=>{}); 
    describe("list display behavior", async(()=>{ 
     describe("filtered-list behavior", async(()=>{ 
      //component.filterList = true; 
      fixture.detectChanges(); 
      fixture.whenStable().then((done:any)=>{ 
       debugger; 
      }); 
     })); 
     describe("unfiltered-list behavior",()=>{ 
      //component.filterList = false; 
     }); 
    })); 
    */ 
}); 

app/Armaturenbrett/dashboard.component

import { Component, Input }  from '@angular/core'; 
import { Router }     from '@angular/router'; 

import { Authentication }   from '../authentication'; 
import { AuthenticationService } from '../authentication.service'; 
import { PatientSummaryService } from '../patient-summary/patient-summary.service'; 
import { PatientSummary }   from '../patient-summary/patient-summary'; 

@Component(
    { 
     moduleId: module.id, 
     selector: 'dashboard', 
     template: ` 
     <div class="container" *ngIf="credentials.valid"> 
      <div class="col-xs-12 filterOptions"> 
       <span class="col-xs-12"> 
        <button class="btn btn-small btn-default pull-right" (click)="toggleFilterView()">Toggle Filters</button> 
        <h4>Filter Options</h4> 
       </span> 
       <span *ngIf="viewFilters"> 
        <label> 
        <input type='checkbox' [(ngModel)]="filterList" /> 
        Filter the list for <strong>only</strong> patients linked to your account. 
        </label> 
        <div class="form-group"> 
         <label>Filter By Patient Name</label> 
         <input class="form-control" [(ngModel)]="nameFilter" placeholder="Patient name in full or in part." /> 
        </div> 
       </span> 
      </div> 
      <h1>Priority Patients</h1> 
      <patient-list [sourceData]="todaysPatientList | staffFilter : acceptableStaff" (clickPatient)="selectPatient($event)"></patient-list> 
      <h1>Patients Records <small>(Not Yet Complete)</small></h1> 
      <patient-list [sourceData]="nonActivePatientList | staffFilter : acceptableStaff" (clickPatient)="selectPatient($event)"></patient-list> 
     </div>`, 
     styles: [ 
       `.filterOptions { 
        background-color: hsla(187, 55%, 90%, 0.5); 
        padding: 1em; 
        border: solid 3px black; 
        border-radius: 1em; 
        margin-bottom: 1em; 
       }` 
      ] 
    } 
) 
export class DashboardComponent { 
    credentials : Authentication = new Authentication(null,null,null); 
    viewFilters: boolean = false; 
    nameFilter: string = ""; 
    filterList: boolean = true; 
    patientSummary: PatientSummary[]; 

    constructor(private patientSummaryService : PatientSummaryService, 
    private authService : AuthenticationService, 
    private router : Router){} 
    ngOnInit(){ 
     var app = this; 
     this.patientSummaryService.updatedList.subscribe(
      (list : PatientSummary[]) => {app.setPatientSummaryList(list);} 
     ); 
     this.authService.newCreds.subscribe(
      (creds : Authentication) => this.credentials = creds 
     ); 
     this.authService.invalidate.subscribe(
      (obj : any) => this.credentials = new Authentication(null,null,null) 
     ); 
    } 
    setPatientSummaryList(list: PatientSummary[]) { 
     var app = this; 
     list.sort((a: PatientSummary, b: PatientSummary) => { 
      var dateA = app.extractDate(a); 
      var dateB = app.extractDate(b); 
      if (dateA > dateB) return 1; 
      if (dateA < dateB) return -1; 
      return 0; 
     }); 
     this.patientSummary = list; 
    } 
    extractDate(item: PatientSummary) { 
     var date = item.arrivalTime; 
     if (date === null || date < item.visit.date) { 
      date = item.visit.date; 
     } 
     return date; 
    } 
    nameFilterFunction(item: PatientSummary) { 
     if (this.nameFilter == "") return true; 
     if (typeof item == "object" && typeof item.name != "undefined") { 
      var index = item.name.indexOf(this.nameFilter); 
      return (index !== -1); 
     } 
     return false; 
    } 
    toggleFilterView() { 
     this.viewFilters = !this.viewFilters; 
    } 


    /** 
    * Returns a list of patients in ascending order (oldest first) of items 
    * that are today and are assigned to a room. 
    */ 
    get todaysPatientList() { 
     var app = this; 
     if (!Array.isArray(this.patientSummary)) return []; 
     var list = this.patientSummary.filter(
      (item: PatientSummary) => { 
       var date = app.extractDate(item); 
       var now = new Date(); 
       var today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); 
       var tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1); 
       return date >= today && date <= tomorrow; 
      }).filter((item: PatientSummary) => { 
       if (typeof item == "object" && typeof item.location == "object" && typeof item.location.room !== null) { 
        return item.location.room != "No Room Assignment"; 
       } else { 
        return true; 
       } 
      }); 
     return list.filter((item) => {return app.nameFilterFunction(item);}); 
    } 
    /** 
    * Returns a list of patients in descending order (most recent first) of items 
    * that do not appear in the todaysPatientList attribute; 
    */ 
    get nonActivePatientList() { 
     if (!Array.isArray(this.patientSummary)) return []; 
     var app = this; 
     var list = this.todaysPatientList; 
     var nonActiveList = this.patientSummary.filter((obj: PatientSummary) => { 
      var index = list.indexOf(obj); 
      return (index == -1); 
     }); 
     nonActiveList.reverse(); 
     return nonActiveList.filter((item) => {return app.nameFilterFunction(item);});; 
    } 
    get acceptableStaff() { 
     if (!this.filterList) { 
      return "any"; 
     } else { 
      var user = "any"; 
      if (this.credentials instanceof Authentication) { 
       user = this.credentials.username; 
      } 
      if (user === null) user = "any"; 
      return user; 
     } 
    }; 
    selectPatient(patient : PatientSummary){ 
     var id = patient.medfaceId; 
     this.router.navigate(['/detail',id]); 
    } 
} 

Update: 9. Februar 2017 03.10 Uhr PCT

Ich nehme an, dass das Problem in meiner Konfiguration oder meiner Code-Basis ist. Aus diesem Grund habe ich heute versucht, Spies anstelle von MockClasses zu verwenden. Durch die Verwendung von Spies hoffte ich, die durch fehlerhafte Anbieter verursachten Komplikationen zu beseitigen. Das System wird beim Testen im Browser geladen. Daher weiß ich, dass die von mir erstellten regulären Anbieter problemlos und ohne Ladefehler funktionieren.

Die Verwendung von Spies hat das Problem nicht behoben. Ich erhalte immer noch den DecoratorFactory-Fehler. Ich werde weiterhin neue Lösungen versuchen, bis eine Antwort gefunden wird. Jede Hilfe wird geschätzt.

+1

Dieser Fehler bedeutet, dass Sie etwas in ein NgModule importieren, das kein geeignetes NgModule ist, das Sie importieren können. Sie wissen das wahrscheinlich schon, aber das ist der Fehler. Der Grund dafür, dass es sich um einen Dekoratorfabrikfehler handelt, besteht darin, dass Angular Dekoratoren nicht direkt verwendet, sondern stattdessen Dekorationsfabriken verwendet, z. Input() anstelle von Input, was verwirrend sein kann, da sich seine Dokumentation auf diese als Dekorateure bezieht. Ich sehe keinen Verweis auf das DynamicTestModule in Ihrem Code, daher muss es eine transitive Abhängigkeit sein. –

+0

Danke! Das wusste ich eigentlich nicht. Ich bin neu in Angular, also scheint so ziemlich alles, was ich lese und höre, eine neue Information zu sein. Alles hilft, danke! –

Antwort

2

Es scheint, dass das Problem durch diese Linie verursacht werden kann. Auch wenn nicht, ist es wahrscheinlich ein Fehler

imports: [ NgModule, RouterModule, FormsModule ], 

anzumerken, dass NgModulenicht ein Winkel 2 Modul aber eine decorator Fabrik, die eine konfigurierte decorator liefert, die wiederum die Zielklasse als Winkel 2-Modul bezeichnet . Der Import als Angular 2-Modul würde diesen Fehler wahrscheinlich auslösen.

+0

Ich werde es erneut versuchen und NgModule entfernen. –

+0

Das hat den Trick gemacht !!! Nachdem ich NgModule entfernt hatte, erhielt ich ein paar zusätzliche Fehler, die jedoch leicht zu beheben waren. NgModule verursachte den Fehler, den ich sah, als Sie vorhergesagt haben. Vielen Dank. –

+1

Ich bin froh, dass ich geholfen habe –

Verwandte Themen