Home > Software design >  TypeError: Cannot read properties of undefined (reading 'fetchPersonnelList')
TypeError: Cannot read properties of undefined (reading 'fetchPersonnelList')

Time:12-01

getting an error as :

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

with my test spec.

full code:

    import { HttpClientModule } from '@angular/common/http';
import { Component } from '@angular/core';
import {
    async,
    ComponentFixture,
    fakeAsync,
    flush,
    TestBed,
    tick,
} from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ActivatedRoute, Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { SharedModule } from '../../../../../shared/shared.module';
import { PersonnelDataService } from '../services/personnel-data.service';
import { testHFSTaleSchema } from './hfs-table.schema';
import { ListPersonnelComponent } from './list-personnel.component';

const mockPersonnelDataService = {
    list$: of(testHFSTaleSchema.rows),
    fetchPersonnelList: function () {
        return { subscribe: () => this.list$ };
    },
    setPageSize: function () {
        return this.list$;
    },
    fetchPaginatedList: () => {},
};

@Component({
    selector: 'app-details-personnel',
    template: '',
})
export class PersonnelDetailsComponent {}

fdescribe('ListPersonnelComponent', () => {
    let component: ListPersonnelComponent;
    let fixture: ComponentFixture<ListPersonnelComponent>;
    let activatedRoute = { url: {} } as ActivatedRoute;
    let service: PersonnelDataService;
    let router;
    const routes = [
        {
            path: 'personnel-details',
            component: PersonnelDetailsComponent,
        },
    ];

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [
                RouterTestingModule.withRoutes(routes),
                SharedModule,
                BrowserAnimationsModule,
                HttpClientModule,
            ],
            declarations: [ListPersonnelComponent],
            providers: [
                {
                    provide: PersonnelDataService,
                    useValue: mockPersonnelDataService,
                },
                { provide: ActivatedRoute, useValue: activatedRoute },
            ],
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(ListPersonnelComponent);
        component = fixture.componentInstance;
        router = TestBed.inject(Router);
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('should call fetchPersonnelList on page Oninit', fakeAsync(() => {
        component.ngOnInit();
        tick(1000);
        expect(service.fetchPersonnelList).toHaveBeenCalled();//error
        flush();
    }));
});

UPDATE

as per forestG suggession i update the code by injecting service. when mock service existing, still i am getting an error as :

Error: <toHaveBeenCalled> : Expected a spy, but got Function. when mock service added, why i am getting this error?

suggestion update

I have updated my code like:

it('should call fetchPersonnelList on page Oninit', fakeAsync(() => {
        const fetchPersonnelListSpy = spyOn(
            service,
            'fetchPersonnelList'
        ).and.returnValue(of([]));
        component.ngOnInit();
        tick(1000);
        expect(fetchPersonnelListSpy).toHaveBeenCalled(); 
        flush();
    }));

it works. but what is the benefit of my mock service? how can I expect my mock data. I can put my data directly in the retunValue part right? any one help me please?

CodePudding user response:

You forgot to get a reference to your service:

   beforeEach(() => {
        fixture = TestBed.createComponent(ListPersonnelComponent);
        component = fixture.componentInstance;
        router = TestBed.inject(Router);
        service = TestBed.inject(PersonnelDataService);  // add this
        fixture.detectChanges();
    });

CodePudding user response:

You should be able to directly spy on the service spyOn(component.service, 'fetchPersonnelList') and use .callThrough which will call the mock function, if you want to prevent calling the mock function and pass some other value then use .returnValue(of([]));

it('should call fetchPersonnelList on page Oninit', () => {
  const fetchPersonnelListSpy = spyOn(component.service, 'fetchPersonnelList').and.callThrough();
  component.ngOnInit();
  expect(fetchPersonnelListSpy).toHaveBeenCalled();
});
  • Related