嗨,我有一个角度为2的分量。我有一个测试。我的测试失败了,因为我出现了以下错误。以下是我在运行ng测试时遇到的错误。
Expected spy create to have been called with
[ <jasmine.objectContaining(Object({ name: 'test', campaign: Object({ id: '123' }) }))> ]
but actual calls were [ Object({ name: 'test', campaign: undefined }) ].
下面是我的测试。
describe('CreateFlightComponent', () => {
let component: CreateFlightComponent;
let fixture: ComponentFixture<CreateFlightComponent>;
let router: Router;
let getCampaignSpy: jasmine.Spy;
let createFlightSpy: jasmine.Spy;
let navigateSpy: jasmine.Spy;
let toastSpy: jasmine.Spy;
let getUserSpy: jasmine.Spy;
let getApprovalPeriodDateSpy: jasmine.Spy;
let getTagOnsSpy: jasmine.Spy;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CreateFlightComponent],
providers: [
FlightsService,
CampaignsService,
ToastService,
AuthenticationService,
SettingsService,
{
provide: ActivatedRoute,
useValue: {
paramMap: of(convertToParamMap({ id: '123' }))
}
},
{ provide: ConfigService, useClass: ConfigServiceMock }
],
imports: [
TranslateModule.forRoot(),
RouterTestingModule,
HttpClientTestingModule
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
const campaignsService = TestBed.get(CampaignsService);
getCampaignSpy = spyOn(campaignsService, 'get').and.returnValue(
of({
id: '123'
})
);
const flightsService = TestBed.get(FlightsService);
createFlightSpy = spyOn(flightsService, 'create').and.returnValue(
of({ id: 'f321' })
);
getTagOnsSpy = spyOn(flightsService, 'getTagOns').and.returnValue(of([]));
spyOn(flightsService, 'getTagOnTargetRecipients').and.returnValue(
of([] as TagOnTargetRecipient[])
);
const toastService = TestBed.get(ToastService);
toastSpy = spyOn(toastService, 'toast');
const authenticationService = TestBed.get(AuthenticationService);
getUserSpy = spyOn(authenticationService, 'getUser').and.returnValue(
of({
account: { features: [{ code: FeatureCode.PROFILES }] } as Account
} as User)
);
const settingsService = TestBed.get(SettingsService);
getApprovalPeriodDateSpy = spyOn(
settingsService,
'getApprovalPeriodDate'
).and.returnValue(of(moment(new Date()).add(7, 'days')));
router = TestBed.get(Router);
navigateSpy = spyOn(router, 'navigate');
});
beforeEach(() => {
fixture = TestBed.createComponent(CreateFlightComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
describe('handleSave', () => {
it('should send a request to create a flight', fakeAsync( () => {
fixture.detectChanges();
tick();
component.handleSave({ currentValue: { name: 'test' }, stepIndex: 1 });
expect(createFlightSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
name: 'test',
campaign: { id: '123' }
})
);
}))
});
});
以下是我的组件类CreateFlightComponent
export class CreateFlightComponent implements OnInit {
campaign: Campaign;
isLoading = true;
isSaving = false;
hasProfileFeature = false;
hasLocationFeature = false;
hasRecipientGatheringFeature = false;
hasParameterisedContactListFeature = false;
hasInteractiveSMSFeature = false;
account: Account;
inventories: Inventory[] = [];
tagOns: TagOn[] = [];
tagOnTargetRecipients: TagOnTargetRecipient[] = [];
approvalPeriodStartDate: Moment;
parameterisedContactList: ParameterisedContactList;
addressProfile: AddressProfile;
constructor(
private router: Router,
private route: ActivatedRoute,
private translateService: TranslateService,
private flightsService: FlightsService,
private campaignsService: CampaignsService,
private toastService: ToastService,
private authenticationService: AuthenticationService,
private settingsService: SettingsService
) {}
ngOnInit() {
this.route.paramMap
.pipe(
tap(() => (this.isLoading = true)),
switchMap(paramMap =>
combineLatest(
this.authenticationService.getUser(),
this.campaignsService.get(paramMap.get('id')),
this.settingsService.getApprovalPeriodDate(),
this.flightsService.getTagOns(),
this.flightsService.getTagOnTargetRecipients(),
this.flightsService.getInventories()
)
)
)
.subscribe(
([user, campaign, date, tagOns, tagOnTargetRecipients, allInventories]) => {
this.isLoading = false;
if (user.account) {
this.account = user.account;
this.inventories = this.account.inventories;
if (this.account.features) {
this.hasProfileFeature = this.account.features.some(
feature => feature.code === FeatureCode.PROFILES
);
this.hasLocationFeature = this.account.features.some(
feature => feature.code === FeatureCode.LOCATIONS
);
this.hasRecipientGatheringFeature = this.account.features.some(
feature => feature.code === FeatureCode.RECIPIENT_GATHERING
);
this.hasParameterisedContactListFeature = this.account.features.some(
feature =>
feature.code === FeatureCode.PARAMETERISED_CONTACT_LIST
);
this.hasInteractiveSMSFeature = this.account.features.some(
feature =>
feature.code === FeatureCode.INTERACTIVE_SMS
);
this.addInteractiveSMS(this.hasInteractiveSMSFeature, allInventories, this.inventories )
}
if (this.account.addressProfile) {
this.addressProfile = this.account.addressProfile;
}
}
this.tagOns = tagOns;
this.tagOnTargetRecipients = tagOnTargetRecipients;
this.campaign = campaign;
console.log(JSON.stringify(this.campaign));
this.approvalPeriodStartDate = date;
},
() => {
this.isLoading = false;
}
);
}
addInteractiveSMS( hasInteractiveSMSFeature:boolean, allInventories: Inventory[] , inventories: Inventory[]) {
let interactiveSMS = allInventories.find(inventory => inventory.code === InventoryCode.INTERACTIVE_SMS);
if(hasInteractiveSMSFeature && interactiveSMS){
inventories.push(interactiveSMS);
}
}
handleSave({
currentValue,
stepIndex
}: {
currentValue: Partial<Flight>;
stepIndex: number;
}) {
const request: Partial<Flight> = {
...currentValue,
campaign: this.campaign
};
const titleKey = 'HEADINGS.FLIGHT_CREATED';
let bodyKey = '';
this.isSaving = true;
this.flightsService
.create(request)
.pipe(
switchMap(flight => {
this.router.navigate(['/flights', flight.id, 'edit'], {
queryParams: { startStepIndex: stepIndex }
});
request.impressionLimit !== flight.impressionLimit
? (bodyKey = 'MESSAGES.IMPRESSIONS_CHANGED')
: (bodyKey = 'MESSAGES.FLIGHT_SAVED_DRAFT');
return request.impressionLimit !== flight.impressionLimit
? this.translateService.get([titleKey, bodyKey], {
name: request.name,
impressions: flight.impressionLimit
})
: this.translateService.get([titleKey, bodyKey], {
name: request.name
});
})
)
.subscribe(
translations => {
this.isSaving = false;
this.toastService.toast({
type: 'success',
title: translations[titleKey],
body: translations[bodyKey],
icon: 'paper-plane',
timeout: 10000
});
},
() => {
this.isSaving = false;
}
);
}
saveAsDraft(currentValue: Partial<Flight>) {
const titleKey = 'HEADINGS.FLIGHT_CREATED';
const bodyKey = 'MESSAGES.FLIGHT_SAVED_DRAFT';
const request: Partial<Flight> = {
...currentValue,
campaign: this.campaign,
parameterisedContactList: this.parameterisedContactList,
status: {
code: FlightStatusCode.DRAFT
}
};
this.isSaving = true;
this.flightsService
.create(request)
.pipe(
switchMap(flight => {
this.router.navigate(['/flights', flight.id, 'edit'], {
queryParams: { startStepIndex: 1 }
});
return this.translateService.get([titleKey, bodyKey], {
name: request.name
});
})
)
.subscribe(
translations => {
this.isSaving = false;
this.toastService.toast({
type: 'success',
title: translations[titleKey],
body: translations[bodyKey],
icon: 'paper-plane',
timeout: 10000
});
},
() => {
this.isSaving = false;
}
);
}
handleUploadFormSubmit(value: ParameterisedContactList) {
this.parameterisedContactList = value;
}
handleCancel() {
this.router.navigate(['/campaigns', this.campaign.id]);
}
}
我的测试正在调用handleSave。我试着调试代码。我在ngOnInit((中的subscribe方法中的this.campaign=campaign语句中放置了一个调试点。然而,它并没有达到调试阶段。感谢您帮助
谢谢
请注意:
更新到以下代码,但我得到了一个错误。
CreateFlightComponent should send a request to create a flight
[object ErrorEvent] thrown
TypeError: Cannot read property 'next' of undefined
describe('CreateFlightComponent', () => {
let component: CreateFlightComponent;
let fixture: ComponentFixture<CreateFlightComponent>;
let router: Router;
let getCampaignSpy: jasmine.Spy;
let createFlightSpy: jasmine.Spy;
let navigateSpy: jasmine.Spy;
let toastSpy: jasmine.Spy;
let getUserSpy: jasmine.Spy;
let getApprovalPeriodDateSpy: jasmine.Spy;
let getTagOnsSpy: jasmine.Spy;
let myActivatedRouteObserver;
beforeEach(() => {
const myActivatedRouteObservable = new Observable((observer) => {
myActivatedRouteObserver = observer;
});
});
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CreateFlightComponent],
providers: [
FlightsService,
CampaignsService,
ToastService,
AuthenticationService,
SettingsService,
{
provide: ActivatedRoute,
useValue: myActivatedRouteObserver
},
{ provide: ConfigService, useClass: ConfigServiceMock }
],
imports: [
TranslateModule.forRoot(),
RouterTestingModule,
HttpClientTestingModule
],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
const campaignsService = TestBed.get(CampaignsService);
getCampaignSpy = spyOn(campaignsService, 'get').and.returnValue(
of({
id: '123'
})
);
const flightsService = TestBed.get(FlightsService);
createFlightSpy = spyOn(flightsService, 'create').and.returnValue(
of({ id: 'f321' })
);
getTagOnsSpy = spyOn(flightsService, 'getTagOns').and.returnValue(of([]));
spyOn(flightsService, 'getTagOnTargetRecipients').and.returnValue(
of([] as TagOnTargetRecipient[])
);
const toastService = TestBed.get(ToastService);
toastSpy = spyOn(toastService, 'toast');
const authenticationService = TestBed.get(AuthenticationService);
getUserSpy = spyOn(authenticationService, 'getUser').and.returnValue(
of({
account: { features: [{ code: FeatureCode.PROFILES }] } as Account
} as User)
);
const settingsService = TestBed.get(SettingsService);
getApprovalPeriodDateSpy = spyOn(
settingsService,
'getApprovalPeriodDate'
).and.returnValue(of(moment(new Date()).add(7, 'days')));
router = TestBed.get(Router);
navigateSpy = spyOn(router, 'navigate');
});
beforeEach(() => {
fixture = TestBed.createComponent(CreateFlightComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should send a request to create a flight', fakeAsync( () => {
fixture.detectChanges();
myActivatedRouteObserver.next(convertToParamMap({ id: '123' }));
component.handleSave({ currentValue: { name: 'test' }, stepIndex: 1 });
expect(createFlightSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
name: 'test',
campaign: { id: '123' }
})
);
}));
});
ngOnInit()
,必须调用fixture.detectChanges()
。
我在您的代码中看到了这一点,因此ngOnInit()
应该正在运行。但是,您的ngOnInit()
代码正在订阅Observablethis.route.paramMap
。我不清楚你在测试中在哪里解析了Observable,这样你的管道和订阅就可以运行了。
当您设置ActivatedRoute
提供程序时,我会创建自己的Observable,您可以完全控制它。
创建Observable:
let myActivatedRouteObserver;
constant myActivatedRouteObservable = new Observable((observer) => {
myActivatedRouteObserver = observer;
}
创建ActivatedRoute:的提供程序
{
provide: ActivatedRoute,
useValue: {
paramMap: myActivatedRouteObservable
}
},
然后,当您想要解析参数映射时:
myActivatedRouteObserver.next(convertToParamMap({ id: '123' }));
您必须在检测到更改后运行此操作,因为在此之前,observable没有订阅。我怀疑这是您问题的根源,Observble在订阅之前就已经解决了。