Search code examples
angularunit-testingjasmineangular-testangular-spectator

Angular ngneat spectator service testing


I am having trouble testing a service injected into an Angular component.

Here is an example scenario I am facing. Let's say I have SampleComponent that has SampleService injected. I want to test whether running handleAction() in SampleComponent calls SampleService.doSomething().

@Component({
...
})
export class SampleComponent {
    constructor(private sampleService: SampleService) { }

    handleAction(): void {
        this.sampleService.doSomething();
    }
}

Trial 1

import { SampleComponent } from './sample.component';
import { waitForAsync } from "@angular/core/testing";
import { createComponentFactory, Spectator } from "@ngneat/spectator";

describe('SampleComponent', () => {
    let spectator: Spectator<SampleComponent>;
    let component: SampleComponent;

    const createComponent = createComponentFactory({
        component: SampleComponent,
        imports: [ CommonModule ],
        declarations: [ SampleComponent ],
        mocks: [ SampleService ]
    });

    beforeEach(waitForAsync(() => {
        spectator = createComponent();
        component = spectator.component;
    }));

    it("should call SampleService.doSomething", () => {
        const sampleService = spectator.inject(SampleService);
        const spySampleServiceFunction = spyOn(sampleService, "doSomething").and.callThrough();

        component.handleAction();
        expect(spySampleServiceFunction).toHaveBeenCalled();
    });
});

Regardless of whether I use and.callThrough() for spyObject or not, I get the following error.

Error: <spyOn>: doSomething has already been spied upon

Trial 2

// same until 'it'
it("should call SampleService.doSomething", () => {
    const sampleService = spectator.inject(SampleService);

    component.handleAction();
    expect(sampleService.doSomething).toHaveBeenCalled();
});

I get the following error.

TypeError: Cannot read properties of undefined (reading 'doSomething')

Trial 3

If I put SampleService in providers, errors are caused due to the dependencies injected to SampleService.

Any sort of advice and suggestions would be appreciated!


Solution

  • Actually on the second look, the code was getting the service as an Input not a dependency, so that was why the test wasn't working. But, I'll post the final code anyways.

    import { SampleComponent } from './sample.component';
    import { waitForAsync } from "@angular/core/testing";
    import { createComponentFactory, Spectator, SpyObject } from "@ngneat/spectator";
    
    describe('SampleComponent', () => {
        let spectator: Spectator<SampleComponent>;
        let component: SampleComponent;
        let sampleService: SpyObject<SampleService>;
    
        const createComponent = createComponentFactory({
            component: SampleComponent,
            imports: [ CommonModule ],
            declarations: [ SampleComponent ],
            mocks: [ SampleService ]
        });
    
        beforeEach(waitForAsync(() => {
            spectator = createComponent();
            component = spectator.component;
            
            sampleService = spectator.inject(SampleService);
            sampleService.doSomething.and.callThrough();
            
            spectator.detectChanges();
        }));
    
        it("should call SampleService.doSomething", () => {
            component.handleAction();
            expect(spySampleServiceFunction).toHaveBeenCalled();
        });
    });