Matt123
Matt123

Reputation: 615

Angular “Cannot read property 'subscribe' of undefined” in Unit Test

I am using Jest to unit test my Angular app, and I keep getting this error TypeError: Cannot read property 'subscribe' of undefined No solution online seems to make sense or work properly. Here's some code:

page-view.component.ts

  @Input() gotPlot!: Observable<void>;
  ...
  ngOnInit() {
    this.initialiseColumnDefs();
    this.gotPlot.subscribe((response) => { //ERROR is occurring on this line
      this.gotPlotValues(response);
    });
  }

page.component.ts

@Component({
  selector: 'page',
  template: `
    <page-view
      [gotPlot]="gotPlotSubject.asObservable()"
    >
    </page-view>
  `,
})

export class PageComponent implements OnInit {
  ...
  public gotPlotSubject: Subject<void> = new Subject<void>();
  ...

  async get_plot(arr: any): Promise<any[]> {

    //This function calls a service and gets 'plotValues'
    (await this.service.get_plot(input)).subscribe((data: any) => {

      //plotValues is set to values gotten from the service here     

      this.gotPlotSubject.next(plotValues);
    });
  }
}

page-view.component.spec.ts

@Component({
  selector: 'page',
  template: `
    <page-view *ngIf="gotPlotSubject.asObservable()" [gotPlot]="gotPlotSubject.asObservable()">
    </page-view>
  `,
})
class PageMock {
  public gotPlotSubject: Subject<void> = new Subject<void>();
  constructor() {}
  ngOnInit() {
    let plotValues: any = [];
    plotValues[0] = 1;
    plotValues[1] = [1, 2, 3];
    plotValues[2] = [2, 3, 4];
    this.gotPlotSubject.next(plotValues);
  }
}

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

  const createComponent = createComponentFactory({
    component: ViewComponent,
    declarations: [
      ViewComponent,
      PageMock,
    ],
    imports: [TranslateModule.forRoot(), MaterialModule, AgGridModule, FormsModule],
    providers: [HttpClient, HttpHandler, NGXLogger, NGXMapperService, HttpBackend, NGXLoggerHttpService, LoggerConfig],
    schemas: [NO_ERRORS_SCHEMA],
  });

  beforeEach(() => {
    spectator = createComponent();
  });

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

Is my PageMock wrong? How do I mock the observable/subscribe correctly? Is there an easier way to do this without using observables or subscribe? Subscribe and Observables seem to make Unit Testing way more of a pain than it should be.

Upvotes: 1

Views: 1428

Answers (1)

AliF50
AliF50

Reputation: 18899

Try doing

@Component({
  selector: 'page',
  template: `
    <page-view *ngIf="gotPlotSubject.asObservable() | async" [gotPlot]="gotPlotSubject.asObservable()">
    </page-view>
  `,
})

Check out the async pipe on the *ngIf. The unwrapped value of the observable on an *ngIf will always be truthy. I would even get rid of the asObservable(). I don't think they are needed but something for you to experiment with.

And you're right, testing with RxJS can be tricky.

Upvotes: 1

Related Questions