Home > Blockchain >  Jasmine unit tests - TypeError: Cannot read properties of undefined (reading 'pipe')
Jasmine unit tests - TypeError: Cannot read properties of undefined (reading 'pipe')

Time:04-26

TypeError: Cannot read properties of undefined (reading 'pipe') at MyComponent.fetchData

I'm getting the above error when running my Jasmine unit tests in Angular. Existing beforeEach's don't like my new fetchData function in my.component.ts's ngOnInit(). All six of my tests in this spec fail with the same error. Any ideas?

my.component.ts

export class MyComponent extends BaseComponent implements OnInit {

  constructor(
    private myService: MyService,
  ) {}

  ngOnInit(): void {

    this.fetchData();

  }

  public fetchData() {
        this.myService.getData()
        .pipe(takeUntil(this.unsubscribe$)).subscribe(  //this.unsubscribe$ gets destroyed in BaseComponent's ngOnDestroy(). Only purpose of BaseComponent is to unsubscribe from observables
          data => {
            if (data) {
              return this.myService.getTypesByCategory(data);
            }
          }
        );
    return;
  }

my.service.ts

export class MyService {

  getData(): Observable<any> {
    return this.httpClient.get('https://myurl.com/myquerystring')
    .pipe(this.showError());
  }

  getTypesByCategory(data) {
                
    for (let region of data.regions) {
          return this.selectType(myArg);
    }
  }

  selectType(myArg): void {
       // do stuff
    
  }
  
}

my.component.spec.ts

import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { of } from 'rxjs';
import { Router } from '@angular/router';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MyService } from 'src/app/my.service';
import { MyComponent } from './mycomponent';

describe('DeviceRegistrationComponent', () => {
  let component: DeviceRegistrationComponent;
  let fixture: ComponentFixture<DeviceRegistrationComponent>;
  let routerSpy: jasmine.SpyObj<Router>;
  let myServiceSpy: jasmine.SpyObj<MyService>;

  beforeEach(
    waitForAsync(() => {
      const myServiceObj = jasmine.createSpyObj('myService', [
        'selectType',
        'getData',
      ]);

      TestBed.configureTestingModule({
        imports: [
          HttpClientTestingModule,
          RouterTestingModule,
          ReactiveFormsModule,
        ],
        declarations: [MyComponent],
        providers: [
          FormBuilder,
          { provide: MyService, useValue: myServiceObj },
        ],
        schemas: [NO_ERRORS_SCHEMA],
      }).compileComponents();


      routerSpy = TestBed.inject(Router) as jasmine.SpyObj<Router>;
      myServiceSpy = TestBed.inject(MyService) as jasmine.SpyObj<MyService>;
      
    }),
  );

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

  it('should be created', () => {
    expect(component).toBeTruthy();

    expect(myServiceSpy.selectType).toHaveBeenCalledWith(true);
  });

  // 5 more tests all fail with the same error

});

CodePudding user response:

Your component expects getData() to return an observable that it then adds a .pipe(...) to. By default the spy object methods return undefined. You need to mock the functions to return values

const myServiceObj = jasmine.createSpyObj('myService', [
        'selectType',
        'getData',
      ]);

You can mock the return value too

myServiceObj.getData
  .and
  .returnValue(of(true));
  • Related