Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular unit test if component method is called according to a data from a service

I can't figure out how to test if a component method is fired or not on service data condition...

service looks like:

@Injectable()
export class SomeService {

    someData() {
        return true;
    }
}

comp:

export class SomeComponent {

    constructor(private someService: SomeService) { 

        if (this.someService.someData()) {
            this.someMethod();
        } else {
            console.log('keep kalm!');
        }
    }

    someMethod() {
        console.log('some method is fired!')
    }
}

test:

describe('SomeComponent', () => {
    let component: SomeComponent;
    let fixture: ComponentFixture<SomeComponent>; 

    let mockSomeService = {
        someData: () => true
    }

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [SomeComponent],
            providers: [
                {
                    provide: SomeService, useValue: mockSomeService
                }
            ]
        })
        .compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(SomeComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('method should be called', () => {
        spyOn(component, 'someMethod'); 

        expect(component.someMethod).toHaveBeenCalled(); 
    });
});

The component someMethod fires but test fails with:

Expected spy someMethod to have been called.

How can I fix this?

Thanks in advance!

like image 726
Mar Avatar asked Dec 29 '17 15:12

Mar


3 Answers

Oke It is fixed! thanks to the answer from @Supamiu

Incase someone will need it in the future:

Move the initialization into ngOnInit, remove fixture.detectChanges(); from beforeEach and execute it in the test. So:

Comp:

constructor(private someService: SomeService) { }

ngOnInit() {
    if (this.someService.someData()) {
        this.someMethod();
    } else {
        console.log('keep kalm!');
    }
}

test:

beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    // fixture.detectChanges(); <<< Remove this
});

it('method should be called', () => {
    spyOn(component, 'someMethod'); 
    fixture.detectChanges(); // trigger ngOnInit here

    expect(component.someMethod).toHaveBeenCalled(); 
});
like image 119
Mar Avatar answered Oct 15 '22 12:10

Mar


you are setting up the spy too late. By the time you mount the spy on service, it has already been constructed and someMethod has been called. So after defining the component call the spy

it('method should be called', () => {
        var spy = spyOn(component, "someMethod").and.callThrough();
        expect(component).toBeDefined();
        expect(spy);
        expect(component.someMethod).toHaveBeenCalled(); 
 });
like image 27
Sachila Ranawaka Avatar answered Oct 15 '22 12:10

Sachila Ranawaka


You have to create the spy before you create the component, because spies can't look in the past and since your method is only called in constructor, it hasn't been called after you created the spy.

You should move your initialization to either ngOnInit method or a simple init() method called in constructor, this way to can call the init method or ngOnInit and check that someMethodhas been called.

like image 29
Supamiu Avatar answered Oct 15 '22 11:10

Supamiu