angular: Testing - HttpTestingController throws errors for valid JSON

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

HttpTestingController throws exception for valid JSON. Failed: Automatic conversion to JSON is not supported for response type. error (see https://github.com/angular/angular/blob/master/packages/common/http/testing/src/request.ts#L159)

But according to http://www.json.org/ valid JSON is:

  • array
  • object
  • string
  • number
  • null
  • true/false

Expected behavior

It should not throw exception and use value as JSON response of http call.

Minimal reproduction of the problem with instructions

const req = httpMock.expectOne('some-url');
req.flush(true);

Environment


Angular version: 5.0.2

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 22
  • Comments: 20 (1 by maintainers)

Commits related to this issue

Most upvoted comments

work-a-round:

const req = httpMock.expectOne('some-url');
req.event(new HttpResponse<boolean>({body: true}));

instead of req.flush(true)

The above workaround simply masks the issue, since no response is actually resolved without calling ‘flush’ or ‘error’. The reason it will appear to succeed is simply due to the specific nature of the testing scenario, for example:

it ("should verify that user is authenticated", () => {
    // calls underlying http post at 'api/account/isAuth'
    service.isAuth().then(response => {
      // does not execute, and so test defaults to success
      console.log("success!");
      expect(response).toBe(true);
    });

    const req = backend.expectOne("api/account/isAuth");
    req.event(new HttpResponse<boolean>({ body: true }));
  });

As stated in the docs, ‘event’ is used for sending HttpEvent responses for things like progress updates, and as such doesn’t appear to have much use unless ‘flush’ or ‘error’ is used to call ‘complete’ or ‘error’ on the underlying observable.

The solution I used was simply to use a ‘truthy’ value in place of the boolean. Any underlying checks against a boolean value can usually be resolved within conditional statements this way, and so any logic checks in the underlying method code should be covered in this scenario:

it ("should verify that user is authenticated", () => {
    service.isAuth().then(response => {
      console.log("success!"); // underlying check successfully calls
      expect(response).toBe(true); // response is 'true', since underlying check against 1 is 'true'
    });

    const req = backend.expectOne("api/account/isAuth");
    // underlying post response body should be 'true', but 1 is truthy, and so will work in most scenarios
    req.flush(1); 
  });

Changing the one to zero in the above test causes the test to fail, and as such achieves the exact same behaviour as I would have expected from using a boolean value in the body of the response.

Angular 8… same issue 😦

I’m still seeing this issue. Any update?

I also couldn’t get @adamlarner’s solution to work, but a simple modification of his workaround is to use double-not !! to convert the flushed number to a boolean:

service.isAuth().then(response => {
  expect(!!response).toBe(true);
});

Another alternative is to flush a string of ‘true’ (or ‘false’) req.flush('true'); and then compare strings:

service.isAuth().then(response => {
  expect(`${response}`).toBe('true');
});

Should just be able to write: req.flush({ body: true })

I found a workaround. But i’m not sure if it is the best solution.

Here what I did until they fix it.

testService.isEnabled().subscribe((result: boolean) => {
  expect(result).toEqual(Observable.of(true));
});

const req = httpMock.expectOne('some-url');
req.flush(Obserbvable.of(true));