Test how API handles invalid JSON syntax request body using node.js
Asked Answered
R

4

11

I would like to test how an REST API handles a POST request that has a body with invalid JSON syntax, for example a missing comma. I'm using node.js to write the API tests. I'm using frisby but I also tried supertest. No luck. With the previous tools, you pass the request body as a JavaScript object, so it's no go. I tried also to pass the invalid JSON as a string without any luck, since a string is also valid JSON (example below). Any ideas?

frisby.create('Ensure response has right status')
    .post('http://example.com/api/books', '{"invalid"}', {json: true})
    .expectStatus(400)
    .toss();
Refurbish answered 2/2, 2015 at 20:23 Comment(6)
Could you provide examples of the string and objects you used ?Girondist
@Girondist Added an example, thanks.Refurbish
If you need this test, there must be a situation when you expect this error might occur. Can you provide a scenario when this error occurs?Rivera
Could you post the superagent code you tried? It seems like that library will only do automatic serialization of the data if it's not already a string.Cobbler
@Cobbler I meant to type supertest in my question. not the superagent package that the former depends on. But you are right, superagent allows this as I found out, reading its docs. Thanks :)Refurbish
@Rivera A developer trying the REST API manually might post invalid JSON or he might use/write code that produces invalid JSON and then posts it to the API.Refurbish
R
7

Using the supertest and mocha packages, you can test an endpoint by posting the invalid JSON like this:

var request = require('supertest');

describe('Adding new book', function(){
  it('with invalid json returns a 400', function(done){
    request('http://example.com').post('/api/books')
      .send('{"invalid"}')
      .type('json')
      .expect('Content-Type', /json/)
      .expect(400)
      .end(function(err, res) {
          console.log(res.error);
          done();
      });
  });
});

The important bit here is type(json). This will set the Content-Type of the request to application/json. With out it, supertest/superagent will default to sending strings as application/x-www-form-urlencoded. Also the invalid JSON is provided as a string and not as a JavaScript object.

Refurbish answered 13/2, 2015 at 17:31 Comment(0)
E
3

I have never used Frisby or superagent, but I find there are two questions here:

1. passing an invalid JSON from client to server using POST method.

Which is not possible because , it will be soon rejected at the client side itself, and you will get error before making a POST request to the server. (because as there are only strings while working with http, the client will itself try to stringify the JSON where it will get stuck with invalid JSON)

2. pass an invalid JSON just as a string

example: POST a string like this using JQuery

 $.post("demo_test_post.asp",
    {
        name: 'pqr:{"abc":"abc",}'    // see there is a comma at the end making JSON invalid
    },
    function(data, status){
        alert("Data: " + data + "\nStatus: " + status);
    });

This will effectively pass the invalid JSON (name in this case) to the server as a srting. But this will require you to parse the string to JSON using JSON.parse() before you can use it. And when you try that you get this:

SyntaxError: Unexpected token p at Object.parse (native) at Object.app.get.res.send.data [as handle] (/home/ubuntu/workspace/TapToBook.js:35:19) at next_layer (/home/ubuntu/workspace/node_modules/express/lib/router/route.js:103:13) at Route.dispatch (/home/ubuntu/workspace/node_modules/express/lib/router/route.js:107:5) at proto.handle.c (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:195:24) at Function.proto.process_params (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:251:12) at next (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:189:19) at Layer.staticMiddleware [as handle] (/home/ubuntu/workspace/node_modules/express/node_modules/serve-static/index.js:55:61) at trim_prefix (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:226:17) at proto.handle.c (/home/ubuntu/workspace/node_modules/express/lib/router/index.js:198:9)

So whichever packages you use for Rest, you can pass invalid JSON as a string, but not use it.

Equivalent answered 10/2, 2015 at 12:51 Comment(1)
Thanks for your answer. I'd prefer to have the answer as a functional test though with one of the packages mentioned in the question. I've since figured out how to do it with supertest at least.Refurbish
H
1

I assume your test want's to validate the server is handling invalid JSON (and doesn't crash). Hopefully returning a 400 bad request.

Since a POST in http is just a string, an option for the test is to use an API that requires you to supply a JSON object.

If you use raw node http, then you can send whatever invalid string you want:

How to make an HTTP POST request in node.js?

There's also the popular request library.

https://github.com/request/request

For example, with the library, your test could pick up the invalid content from a file and post or put. From their docs:

fs.createReadStream('file.json').pipe(request.put('http://example.com/obj.json'))
Hospice answered 10/2, 2015 at 13:2 Comment(1)
Thanks for you answer. I didn't thought of using the request package directly in tests. I would prefer though if the code example in the answer was a full working functional test, preferably with out using an external file to store the invalid JSON.I figured out how to do it with supertest/superagent but the request API does not seem very different, so one could do it with this one as well I guess.Refurbish
O
0

It is actually a simple trick when using npm request library. Here is how I achieved and it is working.

    describe('with invalid JSON, attempt a config api call', () => {
      let response;
      before(async () => {
        const k = "on:true";
        response = await request.put(configURL+ `/0/config/`, {
          json:k,
          headers: {
            authorization: bearer,
            "content-type": "application/json",
          }
        })
      });
      it('should return http 400 OK', () => {
        response.statusCode.should.equal(400);
      });
      it('should have error message as SyntaxError: Unexpected token in JSON body', () => {
        response.body.should.equal("SyntaxError: Unexpected token in JSON body");
      });
    });

Note: Here it is an invalid JSON because ON is without quotes. This will help the testers using request library.

Orchestra answered 24/10, 2019 at 8:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.