Reputation: 3462
I am experiencing many issues trying to validate a service call inside an Angular 5 component function.
@Component({
selector: 'app-example',
templateUrl: './app-example.html',
styleUrls: ['./app-example.css'],
providers: [ PersistanceService, AnotherService ]
})
export class ExampleComponent {
callPersist: boolean = false;
private simpleObj = {
"name": "a",
"age" : 20
}
constructor(private persistanceService: PersistanceService, anotherService: AnotherService) {}
persist() {
if (this.callPersist)
this.persistanceService.persist(this.simpleObj);
else
this.anotherService.terminate();
}
}
In my tests, I want to validate that upon calling persist(), the corresponding service is being called. This is my test case:
it('should call persistService', () => {
let persistService = TestBed.get(PersistanceService); //this is being declared in TestBed.configureTestingModule
spyOn(persistService, 'persist').and.callThrough(); //create spy
component.callPersist = true; //set flag for persistance
fixture.detectChanges(); //update variables in fixture
component.persist(); //call parent method
expect(persistService.persist).toHaveBeenCalled(); // error
expect(persistService).toHaveBeenCalled(); // error
expect(persistService.calls.any()).toBeTruthy(); //error
});
No matter what the expectation is, the result will always be
Expected spy persist to have been called.
The only situation where the expectations are met is when I call the spy directly inside my test case. However, this is of no use to me. I wish to validate my service calls pretty much like Mockito does using .verify();
Is there any chance I am completely wrong about this?
PS: The tests are being ran through Jasmine 2.8.0
Edit: adding beforeEach() method
beforeEach(async() => {
TestBed.configureTestingModule({
declarations: [ ExampleComponent ],
providers: [
PersistanceService,
AnotherService
]
}).compileComponents();
fixture = TestBed.createComponent(ExampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Upvotes: 3
Views: 3939
Reputation: 214175
Let's see what you're trying to test.
You have component where you provided services on component level:
@Component({
...
providers: [ PersistanceService, AnotherService ]
})
export class ExampleComponent {
Then in your test you're providing the same services on the root module level:
TestBed.configureTestingModule({
declarations: [ ExampleComponent ],
providers: [
PersistanceService,
AnotherService
]
}).compileComponents();
As you can guess these services will be completely different instances when test will be run.
How to check it?
const componentPersistService = fixture.debugElement.injector.get(PersistanceService);
const globalPersistService = TestBed.get(PersistanceService);
componentPersistService === globalPersistService // false
See also the doc:
I think you understand now that we need to test service which provided on component level.
Here you go:
it('should call persistService', () => {
const persistService = fixture.debugElement.injector.get(PersistanceService);
const persistSpy = spyOn(persistService, 'persist').and.callThrough(); // create spy
component.callPersist = true; // set flag for persistance
fixture.detectChanges(); // update variables in fixture
component.persist(); // call parent method
expect(persistService.persist).toHaveBeenCalled(); // error
expect(persistSpy).toHaveBeenCalled(); // error
expect(persistSpy.calls.any()).toBeTruthy(); // error
});
Note: if you want to provide custom implementation of component level service then you should use overrideComponent method, for example:
fixture = TestBed.overrideComponent(ExampleComponent, {
providers: { provide: PersistanceService, useClass: PersistanceServiceSpy }
})
.createComponent(ExampleComponent);
Upvotes: 8