Я создаю тест для компонента с именем «DashboardComponent». Тест-тест трудно создать. Карма бросает ошибку «Неожиданное значение« DecoratorFactory », импортируемое модулем« DynamicTestModule ».Нужна помощь в конфигурации Angular2 TestBed. Ошибки DecoratorFactory
Я попытался удалить код до тех пор, пока ошибка не исчезнет, а затем добавит код обратно, пока он снова не появится, чтобы определить источник. Однако это не принесло плодотворных результатов, поскольку код разбивается при использовании нескольких разных конфигураций, и я не могу определить, какая конфигурация вызывает ошибку, и которая вызывает ошибку. Я подозреваю, что плохая конфигурация существует во всех моих неудачных попытках, а некоторые строки кода, такие как добавление вызова it()
, вызывают внезапную видимость ошибки, когда она не была видна раньше.
Надеюсь, что кто-то с большим опытом, чем я, увидит мою ошибку и предоставит вам некоторые советы. У других была такая же проблема на StackOverflow, и решения, которые с ними работали, похоже, не применимы к этой ситуации.
код Диаграмма
Чтобы сделать код база легче переваривается, я создал схему UML, чтобы показать, что я зависимости пытаюсь воспроизвести в конфигурации тестового стенда.
зеленый элемент является элементом проходит испытания. Элементы пакета импортируются в модуль, и у каждого из них есть класс-макет, и мы предоставляем классы-макеты вместо них. Мы должны объявить три компонента, потому что шаблон 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. Я буду продолжать попытки новых решений, пока не будет найден ответ. Любая помощь приветствуется.
Эта ошибка означает, что вы импортируете что-то в NgModule, который не является надлежащим NgModule, который вы можете импортировать. Вероятно, вы уже знаете это, но это то, что указывает ошибка. Причина, по которой он выглядит как заводская ошибка декоратора, заключается в том, что Angular не использует декораторов непосредственно, он использует фабрики декораторов, а не, например. Input() вместо Input, что может сбивать с толку, поскольку его документация относится к ним как к декораторам. Я не вижу ссылки на DynamicTestModule в вашем коде, поэтому он должен быть транзитивной зависимостью. –
Спасибо! На самом деле я этого не знал. Я новичок в Angular, поэтому почти все, что я читаю и слышу, кажется новой информацией. Все помогает, спасибо! –