Cokeroft
Cokeroft

Reputation: 21

Express JavaScript Supertest Expect specific json fields

I'm attempting to write some unit tests for API endpoints, and decided on JavaScript Express w/ Supertest. I've got the basic downs, but running into issues checking the response for a specific field. I want to parse the body and check if an expected field returns and has the correct value. Most everything I've seen online uses this method, but when I try it always passes, even when I enter values I know don't exist in the JSON. Any advice? Here is my code snippet:

describe('GET category', function () {
    it('response w/ only injury returned', function () {
        request('endpoint')
            .get('path')
            .set('header', 'token')
            .expect(200)
            .then(response => {
                console.assert(response.body, "Baseball")
            })
    })
});

I have also tried changing the .then to .expect, with same results. If I do response.body.specificFieldinBody I get similar results. Any help?

Upvotes: 2

Views: 1446

Answers (2)

ggorlen
ggorlen

Reputation: 57344

I see three issues:

  1. console.assert(response.body, "Baseball") only checks whether response.body is truthy. "Baseball" is just the message that prints if it isn't (i.e. Assertion failed: Baseball). You may be looking for

    console.assert(response.body.Baseball, "body.Baseball should be defined")
    

    or you may want to assert that the value for a particular key equals "Baseball"; something like

    console.assert(response.body.injury === "Baseball", "body.injury === 'Baseball'")
    
  2. console.assert just logs the failure to the console, which likely won't be picked up by whatever testing library you're using (Mocha, Jest). I suggest using an assertion library like Chai, Jest's built-in assertions, or at least Node's native assert so the test will show as a failure.

  3. request('endpoint') returns a promise. If the test suite isn't appraised of the asynchronous nature of the test, it'll happily give you an instant pass without actually running any assertions. Use return request('endpoint') to ensure that the test suite awaits for the promise chain to resolve and detects any assertions.

Marking your test async helps reduce the footgun factor and is generally cleaner than .then() or callbacks (less nesting). Here's a complete example you can run with npx mocha server.test.js.

server.test.js:

const assert = require("assert");
const request = require("supertest");
const app = require("./server");

describe("GET category", () => {
  it("response with only injury returned", async () => {
    const response = await request(app).get("/path");
    assert(response.status === 200);
    assert(response.body.injury === "Baseball");
  });

  // ... or use supertest's assertions:
  it("response with only injury returned (alternate approach)", () => {
    return request(app)
      .get("/path")
      .expect(200, {injury: "Baseball"});
  });
});

server.js:

const express = require("express");
const app = express();

app.get("/path", (req, res) => res.json({injury: "Baseball"}));

module.exports = app;

package.json:

{
  "dependencies": {
    "express": "^4.18.3"
  },
  "devDependencies": {
    "mocha": "^10.3.0",
    "supertest": "^6.3.4"
  }
}

Upvotes: 0

hoangdv
hoangdv

Reputation: 16157

You can do with your way - use .then syntax, but I think use Supertest assertion syntax will be good.

This mean, use response.body.should.have.property("Baseball"); instead of console.assert(response.body, "Baseball") (Baseball is your special field).

Or, My suggestion is creating a re-use code: Put a assertion callback function to a next expects section.

const isIncludeField = function (fieldName) {
  return function (res) {
    res.body.should.have.property(fieldName);
  };
}

describe('GET category', function () {
  it('response w/ only injury returned', function () {
    request('endpoint')
      .get('path')
      .set('header', 'token')
      .expect(200)
      .expect(isIncludeField('Baseball')) // 
      .end(done); // call done callback
  })
});

Upvotes: 1

Related Questions