Search code examples
angularunit-testingkarma-jasmineangular-testangular-unit-test

Angular: Testing Http POST method


I have a simple service method that does an http post call to add a todoList:

add(event: any): Observable<TodoList> {
    let todoListToAdd: TodoList = { name: event.target.value, listItems: []};
    return this.http.post<TodoList>("https://localhost:44305/todolist", todoListToAdd);
}

I want to unit test this method and tried like this:

import { TestBed, getTestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

import { TodolistService } from './todolist.service';
import { TodoList } from './todolist';
import { HttpResponse } from '@angular/common/http';

describe('TodolistService', () => {
  let injector: TestBed;
  let service: TodolistService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ HttpClientTestingModule ],
      providers: [ TodolistService ]
    });

    injector = getTestBed();
    service = injector.get(TodolistService);
    httpMock = injector.get(HttpTestingController);
  });

  afterEach(() => {
    httpMock.verify();
  });

  describe('#getTodoLists', () => {
     it('getTodoLists - when called after add was called once, then it should return 3 todo lists', () => {
      const event = { target: { value: "test" } };
      const expectedTodoList: TodoList = { name: event.target.value, listItems: []};

      service.add(event);
  
      const req = httpMock.expectOne("https://localhost:44305/todolist");
      expect(req.request.method).toBe("POST");
      expect(req.request.body).toEqual(expectedTodoList);
      req.flush(expectedTodoList);
    });
  });
});

Why am I getting the following error?

Error: Expected one matching request for criteria "Match URL: https://localhost:44305/todolist", found none.

It is exactly the url that I am calling in the add method, why doesn't it find it?

Thanks in advance for your help


Solution

  • While all your mocks and imports are perfectly fine, you forgot to subscribe to the returned observable. This is important for the underlaying method to actually run. To make it work just subscribe to the stream and inside run your assertions.

    import { TestBed, getTestBed } from '@angular/core/testing';
    import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
    
    import { TodolistService } from './todolist.service';
    import { TodoList } from './todolist';
    import { HttpResponse } from '@angular/common/http';
    
    describe('TodolistService', () => {
      let injector: TestBed;
      let service: TodolistService;
      let httpMock: HttpTestingController;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          imports: [ HttpClientTestingModule ],
          providers: [ TodolistService ]
        });
    
        injector = getTestBed();
        service = injector.get(TodolistService);
        httpMock = injector.get(HttpTestingController);
      });
    
      afterEach(() => {
        httpMock.verify();
      });
    
      describe('#getTodoLists', () => {
        it('getTodoLists - when called after add was called once, then it should return 3 todo lists', () => {
          const event = { target: { value: "test" } };
          const expectedTodoList: TodoList = { name: event.target.value, listItems: []};
    
          service.add(event).subscribe((todoList) => {
            expect(todoList).toEqual(expectedTodoList);
          });
    
          const req = httpMock.expectOne("https://localhost:44305/todolist");
          expect(req.request.method).toBe("POST");
          expect(req.request.body).toEqual(expectedTodoList);
          req.flush(expectedTodoList); // This will actually "run" the mocked request if there are any subscribers
        });
      });
    });