Search code examples
unit-testingjestjssupertest

Using expect.any() with supertest to check response body


I'm trying to use supertest to check res.body with Jest, but the following snippet will always fail

request(app)
  .post('/auth/signup')
  .send(validEmailSample)
  .expect(200, {
    success: true,
    message: 'registration success',
    token: expect.any(String),
    user: expect.any(Object),
  });

But when I rewrite the test to check the body in a callback as follows:

test('valid userData + valid email will result in registration sucess(200) with message object.', (done) => {
  request(app)
    .post('/auth/signup')
    .send(validEmailSample)
    .expect(200)
    .end((err, res) => {
      if (err) done(err);
      expect(res.body.success).toEqual(true);
      expect(res.body.message).toEqual('registration successful');
      expect(res.body.token).toEqual(expect.any(String));
      expect(res.body.user).toEqual(expect.any(Object));
      expect.assertions(4);
      done();
    });
});

The test will pass.

I'm sure it has something to do with expect.any(). As Jest's documentation says that expect.any and expect.anything can only be used together with expect().toEqual, and expect().toHaveBeenCalledWith() I'm wondering if there's any better way to do it, to use expect.any in supertest's expect api.


Solution

  • You can use expect.objectContaining(object).

    matches any received object that recursively matches the expected properties. That is, the expected object is a subset of the received object. Therefore, it matches a received object which contains properties that are present in the expected object.

    app.js:

    const express = require("express");
    const app = express();
    
    app.post("/auth/signup", (req, res) => {
      const data = {
        success: true,
        message: "registration success",
        token: "123",
        user: {},
      };
      res.json(data);
    });
    
    module.exports = app;
    

    app.test.js:

    const app = require('./app');
    const request = require('supertest');
    
    describe('47865190', () => {
      it('should pass', (done) => {
        expect.assertions(1);
        request(app)
          .post('/auth/signup')
          .expect(200)
          .end((err, res) => {
            if (err) return done(err);
            expect(res.body).toEqual(
              expect.objectContaining({
                success: true,
                message: 'registration success',
                token: expect.any(String),
                user: expect.any(Object),
              }),
            );
            done();
          });
      });
    });
    

    Integration test result with coverage report:

     PASS  src/stackoverflow/47865190/app.test.js (12.857s)
      47865190
        ✓ should pass (48ms)
    
    ----------|----------|----------|----------|----------|-------------------|
    File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
    ----------|----------|----------|----------|----------|-------------------|
    All files |      100 |      100 |      100 |      100 |                   |
     app.js   |      100 |      100 |      100 |      100 |                   |
    ----------|----------|----------|----------|----------|-------------------|
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        14.319s
    

    Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47865190