Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print the request and response when a test fails in Jest?

I'm using Supertest and Jest to test a Node.js API.

A sample test has the following format

it('Read a note for a user', (done) => {
      request(graphqlURL)
        .post('/graphql')
        .set(baseHeaders())
        .send({
          query: graphQLQuery
        })
        .end((err, res) => {
          expect(res.status).toBe(200);          
          done();
        })

    });

Currently when the expectation fails, the following gets logged

expect(received).toBe(expected) // Object.is equality

    Expected: 200
    Received: 404

I'd also like to log the request and the response alongside the failed tests to have more context while debugging.

Is there a way to print those as well, only for the tests which are failing?

like image 300
dsinecos Avatar asked Mar 11 '19 05:03

dsinecos


2 Answers

expect works by throwing an Error when an expectation fails.

The message property of the Error is what gets printed in the test report.

I suppose if you want to use an existing expectation and just want to augment the fail message with additional data you can catch the Error, append your additional data to the message property, then throw the Error again like this:

it('Read a note for a user', (done) => {
  request(graphqlURL)
    .post('/graphql')
    .set(baseHeaders())
    .send({
      query: graphQLQuery
    })
    .end((err, res) => {
      try {
        expect(res.status).toBe(200);
      } catch (err) {
        // --- add additional data to the error message here ---
        err.message = `${err.message}\n\nfailing query: ${graphQLQuery}`;
        throw err;  // throw the error so test fails as expected
      }
      done();
    })
});
like image 109
Brian Adams Avatar answered Oct 17 '22 14:10

Brian Adams


You could create a custom matcher that logs the response when an expectation fails:

expect.extend({
  statusCode(expected, response) {
    const { status } = response
    const pass = expected === status

    if (pass) {
      return {
        message: () =>
          `expected ${status} to be ${expected}`,
        pass: true
      }
    } else {
      return {
        message: () =>
          `expected ${status} to be ${expected}. Response: ${response}`,
        pass: false
      }
    }
  }
})

Then in your test, use the custom matcher instead of the typical expect:

it('Read a note for a user', (done) => {
  request(graphqlURL)
    .post('/graphql')
    .set(baseHeaders())
    .send({
      query: graphQLQuery
    })
    .end((err, res) => {
      expect.statusCode(200, res)     
      done()
    })
})

Unfortunately, there isn't really a way to access the HTTP request using supertest. But you could add any arbitrary information about the request that you do have to the signature of your custom matcher.

like image 29
djfdev Avatar answered Oct 17 '22 15:10

djfdev