Angular 5 Jasmine Error: Expected one matching request for criteria found none
Asked Answered
O

8

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?

Oslo answered 8/6, 2018 at 7:53 Comment(1)
did you try without the baseUrl, it works for me : .expectOne("/paramX/123");Khano
C
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

Coppersmith answered 10/10, 2018 at 9:54 Comment(2)
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.Dunkle
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 :)Scorpius
F
18

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);
Flagler answered 8/6, 2018 at 8:10 Comment(7)
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.Oslo
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.Flagler
@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);Knp
@Knp 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.Flagler
@trichetriche I would appreciate if you could perhaps show me an example of that?Knp
expectOne(req => console.log(req));Flagler
be sure the url be the same URL like in you service.Pegpega
A
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();

})));
Alexina answered 12/9, 2018 at 21:0 Comment(0)
B
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.

Belize answered 26/11, 2020 at 13:39 Comment(0)
R
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);
      });
Risk answered 30/11, 2021 at 7:20 Comment(0)
A
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
*/
Arterial answered 6/8, 2021 at 3:25 Comment(0)
C
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);
Christmann answered 24/5, 2022 at 9:52 Comment(0)
F
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.

Fovea answered 15/5, 2023 at 8:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.