2017-02-09 3 views
0

Я создаю тест для компонента с именем «DashboardComponent». Тест-тест трудно создать. Карма бросает ошибку «Неожиданное значение« DecoratorFactory », импортируемое модулем« DynamicTestModule ».Нужна помощь в конфигурации Angular2 TestBed. Ошибки DecoratorFactory

Я попытался удалить код до тех пор, пока ошибка не исчезнет, ​​а затем добавит код обратно, пока он снова не появится, чтобы определить источник. Однако это не принесло плодотворных результатов, поскольку код разбивается при использовании нескольких разных конфигураций, и я не могу определить, какая конфигурация вызывает ошибку, и которая вызывает ошибку. Я подозреваю, что плохая конфигурация существует во всех моих неудачных попытках, а некоторые строки кода, такие как добавление вызова it(), вызывают внезапную видимость ошибки, когда она не была видна раньше.

Надеюсь, что кто-то с большим опытом, чем я, увидит мою ошибку и предоставит вам некоторые советы. У других была такая же проблема на StackOverflow, и решения, которые с ними работали, похоже, не применимы к этой ситуации.

код Диаграмма

Чтобы сделать код база легче переваривается, я создал схему UML, чтобы показать, что я зависимости пытаюсь воспроизвести в конфигурации тестового стенда.

enter image description here

зеленый элемент является элементом проходит испытания. Элементы пакета импортируются в модуль, и у каждого из них есть класс-макет, и мы предоставляем классы-макеты вместо них. Мы должны объявить три компонента, потому что шаблон DashboardComponent относится к PatientListComponent, а шаблон PatientListComponent основан на PatientListItemComponent.

Код & Файлы

Это моя надежда не написать роман в этом вопросе, так что я буду добавлять новые файлы & код, если они просят. Пока они не будут запрошены, я предоставлю те файлы, которые наиболее актуальны для определения проблемы.

приложение/панель/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; 
     }); 
    })); 
    */ 
}); 

приложение/приборная панель/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; 
     }); 
    })); 
    */ 
}); 

приложение/панель/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]); 
    } 
} 

Обновление: 9 февраля 2017 года 15:10 PCT

Я предполагаю, что проблема в моей конфигурации или в моей базе кода. По этой причине я попытался сегодня использовать Spies вместо MockClasses. Используя шпионов, я надеялся устранить осложнения, вызванные наличием ошибочных поставщиков. Система загружается при тестировании в браузере, поэтому я знаю, что обычные поставщики, которые я создал, работают хорошо и без ошибок загрузки.

Использование шпионов не помогло. Я до сих пор получаю ошибку DecoratorFactory. Я буду продолжать попытки новых решений, пока не будет найден ответ. Любая помощь приветствуется.

+1

Эта ошибка означает, что вы импортируете что-то в NgModule, который не является надлежащим NgModule, который вы можете импортировать. Вероятно, вы уже знаете это, но это то, что указывает ошибка. Причина, по которой он выглядит как заводская ошибка декоратора, заключается в том, что Angular не использует декораторов непосредственно, он использует фабрики декораторов, а не, например. Input() вместо Input, что может сбивать с толку, поскольку его документация относится к ним как к декораторам. Я не вижу ссылки на DynamicTestModule в вашем коде, поэтому он должен быть транзитивной зависимостью. –

+0

Спасибо! На самом деле я этого не знал. Я новичок в Angular, поэтому почти все, что я читаю и слышу, кажется новой информацией. Все помогает, спасибо! –

ответ

2

Похоже, проблема может быть вызвана этой линией. Даже если нет, то, скорее всего, ошибка

imports: [ NgModule, RouterModule, FormsModule ], 

Обратите внимание, что NgModule является не углового 2 модуля, но декоратор фабрика, которая возвращает сконфигурированный декоратор, который, в свою очередь обозначает целевой класс как Угловые 2 модуля , Импорт его как модуля с угловым 2, вероятно, приведет к этой ошибке.

+0

Я попробую еще раз и удалю NgModule. –

+0

Это сделало трюк !!! После удаления NgModule я получил несколько дополнительных ошибок, но их было легко исправить. NgModule вызвал ошибку, которую я видел, как вы предсказывали. Спасибо. –

+1

Я рад помочь –

Смежные вопросы