malvadao
malvadao

Reputation: 3462

Is it possible to validate a service call inside an Angular component?

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

Answers (1)

yurzui
yurzui

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

Related Questions