Search code examples
angularjasminekarma-jasmineangular-test

Error in angular unit test cases: TypeError: this.userService.currentUser.subscribe is not a function


I am getting this error while running angular unit test cases:

Test Result

SidebarComponent
   × should create
    TypeError: this.userService.currentUser.subscribe is not a function

sidebar.component.spec.ts

describe('SidebarComponent', () => {
  let fixture: ComponentFixture<SidebarComponent>;
  let mockUserService;

  beforeEach(() => {
    mockUserService = jasmine.createSpyObj(['currentUser']);

    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      declarations: [SidebarComponent],
      schemas: [NO_ERRORS_SCHEMA],
      providers: [{ provide: UserService, useValue: mockUserService }]
    });

    fixture = TestBed.createComponent(SidebarComponent);
  });

  fit('should create', () => {
    mockUserService.currentUser.and.returnValue(of('Here goes an object'));
    fixture.detectChanges();
    expect(SidebarComponent).toBeTruthy();
  });
});

sidebar.component.ts

ngOnInit() {
    this.userService.currentUser.subscribe(currentUser => {
        // Some code here
    });
}

package.json

"devDependencies": {
    "@types/jasmine": "2.8.8",
    "@types/jasminewd2": "2.0.3",
    "@types/node": "9.6.23",
    "jasmine-core": "2.99.1",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "4.2.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "2.0.0",
    "karma-coverage-istanbul-reporter": "1.4.3",
    "karma-jasmine": "2.0.1",
    "karma-jasmine-html-reporter": "1.4.0",
    "karma-junit-reporter": "1.2.0",
    "karma-spec-reporter": "0.0.32",
    "protractor": "6.0.0",
    "rxjs-tslint": "0.1.7",
}

user.service.ts

@Injectable({ providedIn: 'root'})
export class UserService {
  private currentUserSubject = new BehaviorSubject({});
  public currentUser: Observable<User> = this.currentUserSubject.asObservable().pipe(distinctUntilChanged());

  setUser(user) {
      this.currentUserSubject.next({ ...newUser });
  }
}

As far I know to solve this question we need to use of in following statement:

mockUserService.currentUser.and.returnValue(of('Here goes an object'));

where of is imported from 'rxjs'. When I log the value of of('Here goes an object') it shows that it's observable.

How can I resolve the issue?


Solution

  • After doing some work on this test, I found that we cannot use spyOn(userService, 'currentUser'). The reason is clear that the currentUser is not a function, but a variable in which we have assigned an observable. SpyOn will create a fake function on this, but what we need is an observable. So we can use userService.setUser method to set the value of currentUser appropirately.

    sidebar.component.spec.ts

    describe('SidebarComponent', () => {
      let component: SidebarComponent;
      let fixture: ComponentFixture<SidebarComponent>;
      let userService: UserService;
    
      beforeEach(done => {
        TestBed.configureTestingModule({
        imports: [HttpClientTestingModule, RouterTestingModule],
        declarations: [SidebarComponent],
        schemas: [NO_ERRORS_SCHEMA]
      })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(SidebarComponent);
        component = fixture.componentInstance;
    
        userService = TestBed.get(UserService);
        userService.setUser(userInfo);
    
        fixture.detectChanges();
        done();
      });
     });
    
     it('should create', done => {
       expect(component).toBeTruthy();
       done();
     });
    })