Error: Expected no open requests, found 1

I am getting this error when I try to execute HTTP unit test cases.

I am using Angular 5. How can I resolve this?

Below is my code for normal GET. Below code just brings normal GET.

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

import { DangerService } from './danger.service';
import { DangerFlag } from '../danger.model';


describe('DataService Tests', () => {
    let dataService: DangerService;
    let httpTestingController: HttpTestingController;

    let testDangerFlags: DangerFlag[] = [ "sample data" ]

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

    dataService = TestBed.get(DangerService);
    httpTestingController = TestBed.get(HttpTestingController);
});

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

fit('should get all danger flags', () => {
    dataService.getDangerFlagDetails()
        .subscribe((data: DangerFlag[]) => {
            expect(data.length).toBe(3);
        });
    });
});

Solution 1:

Expected no open requests, found 1

This happens when you make a mock request, but don't 'complete/close' it. An open request may stay open after a test is run, eventually memory leaking, especially if the test is ran multiple times.

Subscribing to a mock request calls it as far as the client side is concerned but does not 'complete' it as far as the backend is concerned. 'Completing' a request can be done in a number of ways;

backend = TestBed.get(HttpTestingController)

  1. backend.expectOne(URL) - this will both test for a url, and 'close' the backend call. This will not test for params, and will fail if your query has params in it.
  2. backend.expectNone(URL) - in case you're testing for urls that have params, expectOne() wont work. You'll have to use backend.match(). Match does not auto close the backend api call, so you can expectNone() after it to close it out.
  3. .flush(RESPONSE) - flush will force-send a response for the http call, and subsequently close the call. Note: if calling flush on a match(), watch out for match returning an array, i.e. backend.match(...)[0].flush({})

Any of these methods will close out the http request, and make backend.verify() behave.

References

  • You can find in depth examples, and more explanations here
  • expectOne() and match() return an instance of TestRequest
  • expectNone() always returns void

Solution 2:

I also faced this issue today. Add expectOne function call

it('should get all danger flags', () => {
   const actualDangerFlags = createDangerFlagResponse();
   dataService.getDangerFlagDetails()
       .subscribe((actualDangerFlags) => {
        expect(data.length).toBe(3);
     });
   });

   const httpRequest = httpTestingController.expectOne(BASE_URL + relativeURL);
   expect(httpRequest.request.method).toBe('GET');
   httpRequest.flush(actualDangerFlags);
});

createDangerFlagResponse(): DangerFlag[] {
    return /* DangerFlag Array */
}