Test Observable that is piped and uses async pipe

Viewed 2104

I have the following situation. I have an Observable, myObservable$ initialized in ngOnInit. When that happens, the observable is tapped to copy the last value for other purposes. Aside from that, the observable is bound to something my html using the async pipe. How can I test that my tapped function is happening correctly, using jasmine karma?

html:

<input [ngModel]="myObservable$ |async">

ts:

ngOnInit():void {
    this.myObservable$ = this.service.getThings()
      .pipe(tap(value=>this.otherProperty=value))
}

I want to test, in this instance, that this.otherProperty actually has the value. How can I test this?

1 Answers

You should install the spy onto this.service.getThings() method and returns a synchronous observable whose value is available immediately. Then, you can subscribe to it on the ngOnInit method of the component. At last, make an assertion for the otherProperty to check the value. For more info, see Component with async service

E.g. using angular v11+

example.component.ts:

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { ExampleService } from './example.service';

@Component({
  selector: 'app-example',
  template: '<input [ngModel]="myObservable$ |async">',
})
export class ExampleComponent implements OnInit {
  myObservable$: Observable<string>;
  otherProperty: string;
  constructor(private service: ExampleService) {}

  ngOnInit() {
    this.myObservable$ = this.service
      .getThings()
      .pipe(tap((value) => (this.otherProperty = value)));
  }
}

example.service.ts

import { Injectable } from '@angular/core';
import { of } from 'rxjs';

@Injectable()
export class ExampleService {
  constructor() {}
  getThings() {
    return of('your real implementation');
  }
}

example.component.spec.ts:

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { of } from 'rxjs';
import { ExampleComponent } from './example.component';
import { ExampleService } from './example.service';

fdescribe('65479995', () => {
  let fixture: ComponentFixture<ExampleComponent>;
  let component: ExampleComponent;
  let exampleServiceSpy: jasmine.SpyObj<ExampleService>;
  beforeEach(
    waitForAsync(() => {
      exampleServiceSpy = jasmine.createSpyObj('ExampleService', ['getThings']);
      exampleServiceSpy.getThings.and.returnValue(of('fake implementation'));

      TestBed.configureTestingModule({
        declarations: [ExampleComponent],
        imports: [FormsModule],
        providers: [{ provide: ExampleService, useValue: exampleServiceSpy }],
      })
        .compileComponents()
        .then(() => {
          fixture = TestBed.createComponent(ExampleComponent);
          component = fixture.componentInstance;
        });
    })
  );
  it('should pass', () => {
    expect(component.otherProperty).toBeUndefined();
    fixture.detectChanges();
    expect(component.otherProperty).toBe('fake implementation');
    expect(exampleServiceSpy.getThings).toHaveBeenCalled();
  });
});

test result:

================================================================================
āœ” Browser application bundle generation complete.
āœ” Browser application bundle generation complete.
Chrome Headless 80.0.3987.87 (Mac OS 10.13.6): Executed 2 of 47 (skipped 45) SUCCESS (0.17 secs / 0.063 secs)
TOTAL: 2 SUCCESS

enter image description here

Related