Reputation: 4634
I have a TypeScript ModelService
with an edit
function:
edit(model: Model): Observable<Model> {
const body = JSON.stringify(model);
return this.http.put(`/models/edit/${model.id}`, body));
}
And I have a TypeScript EditComponent
with an edit
function that subscribes to the service and navigates when it gets the response:
edit(model: Model): void {
this.service
.edit(model)
.subscribe(() => this.router.navigate([`/models/details/${model.id}`]);
}
What is the best way to test this component's edit
function?
I have a Jasmine test that does this:
// Setup
TestBed.configureTestingModule({
declarations: [EditComponent],
providers: [
{
provide: ModelService,
useValue: jasmine.createSpyObj('ModelService', ['edit'])
}
]
});
const fixture = TestBed.createComponent(EditComponent);
const component = fixture.componentInstance;
const modelService = fixture.debugElement.injector.get(ModelService);
fixture.detectChanges();
// Test
it('should call edit', () => {
fakeAsync(() => {
component.edit(model);
expect(modelService.edit).toHaveBeenCalled();
});
});
But with this test, I always get SPEC HAS NO EXPECTATIONS
when it runs. My understanding of fakeAsync
is that it runs synchronously so I thought this would work.
I've also tried using numerous variations of async
, tick()
, and done()
, but those either give the same message or fail with Cannot read property 'subscribe' of undefined
when calling the component's edit
function.
In other tests, I've been able to use return fixture.whenStable().then()
and that works fine (as described here), but I don't think it works here since the component function is returning void
instead of a Promise.
What is a better way to test this component function?
Upvotes: 5
Views: 6406
Reputation: 636
For SPEC HAS NO EXPECTATIONS
That doesn't seem like the right way to use fakeAsync
and that is why it said no expectations. It should be:
it('should call edit', fakeAsync(() => {
component.edit(model);
expect(modelService.edit).toHaveBeenCalled();
});
Anyway, the modelService.edit()
is actually a call that can be expected synchronously, because it is called inside component.edit()
.
So you can simply test it like this:
it('should call edit', () => {
component.edit(model);
expect(modelService.edit).toHaveBeenCalled();
});
For Cannot read property 'subscribe' of undefined
Because you create spy object without any returns. Hence, modalService.edit()
return undefined
and cannot be read property 'subscribe'. In this case, I normally stub its result by creating new Observable or using of() and return values that this component may need to interact with.
jasmine.createSpyObj('ModelService', { edit: of() })
Upvotes: 2