[Fixed] How to spoof Observable using spyOn?

Issue

I wrote service that request JSON via http:

export class TodosService {
  constructor(private http: HttpClient) {}
  getTodos(): Observable<any> {
    return this.http.get<any>('https://jsonplaceholder.typicode.com/todos');
  }
}

The component is assigned a value from the service:

export class TodosComponent implements OnInit {
  todos: any;
 
  constructor(private todosService: TodosService) {}
 
  ngOnInit() {
    this.todosService.getTodos().subscribe((todos) => {
      this.todos = todos;
    });
  }
}

I would like to test it. There is the unit-test:

describe('Page1Component', () => {
  let component: Page1Component;
  let fixture: ComponentFixture<Page1Component>;
  let spy: any;
  let todosService: TodosService;
 
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [Page1Component],
      imports: [HttpClientModule],
      providers: [TodosService],
    }).compileComponents();
  });
 
  beforeEach(() => {
    fixture = TestBed.createComponent(Page1Component);
    component = fixture.componentInstance;
    fixture.detectChanges();
    todosService = TestBed.inject(TodosService);
  });
 
  it('should fill todos', () => {
    const todos = of([
      {
        completed: false,
        id: 1,
        title: 'title1',
        userId: 1,
      },
    ]);
    spyOn(todosService, 'getTodos').and.returnValue(todos);
    component.ngOnInit();
    expect(component.todos).toEqual(todos);
  });
});

I got the following error message:

Expected [ Object({ completed: false, id: 1, title: ‘title1’, userId:
1 }) ] to equal Observable({ _isScalar: false, _subscribe: Function
}).

I try to use the following mock:

const todos = [
  {
    completed: false,
    id: 1,
    title: 'title1',
    userId: 1,
  },
];

But in this case i get the following popup in my IDE:

Argument of type ‘{ completed: boolean; id: number; title: string;
userId: number; }[]’ is not assignable to parameter of type
‘Observable’.

Please, help me fix this unit-test

Solution

You’re pretty close with what you’re trying, but you’re comparing an array with an observable on the expect matcher. You need to compare the result from the observable

  const data = [
    {
      completed: false,
      id: 1,
      title: 'title1',
      userId: 1,
    },
  ]
  const todosObservable = of(data);
  spyOn(todosService, 'getTodos').and.returnValue(todosObservable);
  component.ngOnInit();
  expect(component.todos).toEqual(data);

The above snippet will work fine, but I generally prefer using the HttpClientTestingModule, it’s handy as you don’t have to mock the services as often

Leave a Reply

(*) Required, Your email will not be published