24

I have a very simple service call and a jasmine test for it.

Service call:

myServiceCall(testId: number) : void {
    const url = `${this.url}/paramX/${testId}`;
    this.http.put(url, {},{headers: this.headers}).subscribe();
}

My Test Method:

it('should call myServiceCall', inject([MyService], (service: MyService) => {
    let testId = undefined;
    service.myServiceCall(testId);
    let req = httpMock.expectOne(environment.baseUrl + "/paramX/123");

    expect(req.request.url).toBe(environment.baseUrl + "/paramX/123");
    expect(req.request.body).toEqual({});

    req.flush({});
    httpMock.verify();
}));

I get of course an exception as I expect the url parameter to be "123"and not undefined like in this test case scenario.

Error: Expected one matching request for criteria "Match URL: http://localhost:8080/myservice/paramX/123", found none.

What I don't understand is why the test framework says

found none

although the request is made. Is there any possibility to let the test framework tell me what other actual calls were made, similar to mockito's verify?

mrkernelpanic
  • 4,268
  • 4
  • 28
  • 52

8 Answers8

21

My problem is solved. After I added to params to the URL (if you use params).

let results = { param: 'results', value: '50' };
url = `${api.url}${route.url}?${results.param}=${results.value}`;

HttpTestingController always display only URL without params, but if used expectOne(url) it use a URL with query string like that: http://example.com/path/to/page?name=ferret&color=purple

Yuri
  • 4,254
  • 1
  • 29
  • 46
  • 3
    This was my problem as well in Angular 6. HttpTestingController reported the URL for a DELETE request *without params*, but was making the request with params. As soon as I matched the params in the URL as well, the test passed. – RoboBear Jan 29 '19 at 18:44
  • if you're expecting a date in the query string, it's quite easy to forget the month argument in the date constructor is zero based and as a result you will be scratching your head for a few minutes :) – JWallace Sep 23 '20 at 14:42
17

You've read the error wrong, let me rephrase it for you :

Error: Expected one matching request [...], found none.

This simply means that your URL doesn't match.

What you can do is add a console log of your URL with

console.log(req.request.url);

Or you can simply try to match the request.

Other solution : since you rely on environment variables, you can run this test instead :

expect(req.request.url.endsWith("/paramX/123")).toEqual(true);
  • I don't want to put console.logs into my code, I expect that the angular http client testing framework offers me a better exception output - if possible at all. – mrkernelpanic Jun 08 '18 at 08:14
  • 13
    Well it doesn't. And I don't tell you to put the console log in production, I'm telling you so that you can see why your URL isn't matching. You can delete it afterwards. –  Jun 08 '18 at 08:15
  • 2
    @trichetriche can you explain how you can log the request.url if it fails to get the request - error at this line: `let request= httpMock.expectOne(url);` – matchifang Oct 11 '18 at 14:10
  • 2
    @matchifang `expectOne(url: string)` is one of the signatures : you have 3. One of them is `expectOne(matchFn: Function)` : you can provide a callback function, that has an `HttpRequest` object as the parameter : by logging this object, you can get the URL that has been called. –  Oct 11 '18 at 14:22
  • @trichetriche I would appreciate if you could perhaps show me an example of that? – matchifang Oct 11 '18 at 14:24
  • 2
    `expectOne(req => console.log(req));` –  Oct 11 '18 at 14:25
  • be sure the url be the same URL like in you service. – danywalls Sep 29 '20 at 14:13
3

You should have your test inside a fakeAsync and call tick() at the end of your test. like

it('should call myServiceCall', inject([MyService], fakeAsync((service: MyService) => {
    let testId = undefined;
    service.myServiceCall(testId);
    let req = httpMock.expectOne(environment.baseUrl + "/paramX/123");

    expect(req.request.url).toBe(environment.baseUrl + "/paramX/123");
    expect(req.request.body).toEqual({});

    req.flush({});
    httpMock.verify();
    tick();

})));
saidutt
  • 289
  • 1
  • 7
1

You are already calling httpMock.verify(), which should fail if there are unexpected requests, and log some information about those requests to the console. If your expectOne failed with a "found none", and verify did not fail, then your service must not actually have called http.put(). Add some logging or step through the test in a debugger to see what's actually happening.

As other answers have pointed out, this could be due to timing issues. Your service call does not return an Observable or Promise so your spec can't tell when it finishes. This means you'll have to manipulate time with waitForAsync or fakeAsync.

Coderer
  • 25,844
  • 28
  • 99
  • 154
1

Here is a work-around, which I used to test the services.

it('should call myServiceCall', (done) => {
        const expectedURL = `/paramX/123`;
        const inputResponse = {id: '123', ...}; // if you want to verify the response
        const expectedResponse = {id: '123', ...}; // if you want to verify the response
        const spy = spyOn<any>(service, 'get').and.returnValue(of(inputResponse));
        let result: any;
        const req = service.myServiceCall().subscribe((t) => {
          result = t;
        });
    
        expect(spy).toHaveBeenCalled();
        expect(spy.calls.mostRecent().args[0]).toEqual(expectedURL);
    
        setTimeout(() => {
          expect(result).toEqual(expectedResponse);
          done();
        }, 1);
      });
0

Also when using Jest - make sure of what environment you are using. The environment needs to be jsdom. If it is not, and you don't want to mess around with global settings - add the following to your file head:

/**
* @jest-environment jsdom
*/
Vega
  • 27,856
  • 27
  • 95
  • 103
Dmitry R
  • 5
  • 1
0

Your URL should match, along with params, what you have in expectOne() when you make a call.

  const response = {};

    service.yourMethod('it should match').subscribe((data: any) => {
        expect(data).not.toBeUndefined();
        done();
    });

    const testRequest = httpMock.expectOne('it should match');
    testRequest.flush(response);
VKD
  • 16
  • 2
0
const req = testController.expectOne('http://localhost:3333/api/some-endpoint-name');

I had similar issue. I used the above line. Also I did the button click before the above line.

Mohsen
  • 971
  • 2
  • 11
  • 29