0

Can I use only JEST to test my rest API endpoints in express? I've searched several articles and also saw some of the questions of stackoverflow to see how can I do this. But the problem is for testing in express most of the people are using mocha/chai or supertest. But I want to use only JEST in my test. Is this possible?

this is my code so far where I want to implement this test:

index.js

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

app.post('/insert', function (req, res, next) {

    const values = req.body; //name, roll

      pool.query(`INSERT INTO student SET ?`, [values], (err, result) => {

        if (err){
          let err = new Error('Not Connected');
          next(err);
      } else {
          res.status(201).json({ msg: `added ${result.insertId}`});
          console.log(result);
        }

      });

});

what i've tried so far is : index.test.js:

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

app.use('../routes');

test('Test POST, Success Scenario', async () => {
    const response = await app.post('/insert')({
        const values //dummy values will be insert here
    });

    expect(response.statusCode).toBe(200);

});

I know my test code is not correct, it's just a pseudocode I'm actually confused how I will hit the end point here

Lin Du
  • 88,126
  • 95
  • 281
  • 483
Insane DA
  • 323
  • 4
  • 16
  • What specific tests do you want to write? Please update your question with at least the pseudocode for the tests and what you have tried so far. That would determine which platform/tool/library would best serve the purpose. – Alexander Staroselsky Jun 17 '19 at 16:45
  • edited, please check now @AlexanderStaroselsky – Insane DA Jun 17 '19 at 16:55
  • 1
    It looks like your are trying to do more of an integration test instead of a unit test. Libraries such as supertest are specifically designed/developed to run applications like express, make requests against specific endpoints, and return responses/errors. Jest is designed/developed for unit testing. If you look at [An Async Example](https://jestjs.io/docs/en/tutorial-async), it even mentions "Because we don't want to go to the network in our test, we are going to create a manual mock for our ". Jest may simply not be the ideal tool for this type of testing. – Alexander Staroselsky Jun 17 '19 at 16:59
  • Can you clarify why for [integration tests](https://stackoverflow.com/questions/5357601/whats-the-difference-between-unit-tests-and-integration-tests) like this you wouldn't be open to using something like supertest which is designed for this type of testing? – Alexander Staroselsky Jun 17 '19 at 17:02
  • i actually want to do unit testing not integration that's why i mentioned my test code might not be right. – Insane DA Jun 17 '19 at 17:06
  • This is a bigger conversation regarding testing approaches, but you could still use Jest with supertest in your example (instead of mocha + supertest) to mock the call to the database for example. – Alexander Staroselsky Jun 17 '19 at 17:10
  • okay i will give it a try and will research on it . thanks :) – Insane DA Jun 17 '19 at 17:14

1 Answers1

1

Here is the unit test solution for testing Nodejs web framework express REST API ONLY USING JEST:

index.js:

const express = require('express');
const { Pool } = require('pg');

const app = express();
const pool = new Pool();

app.post('/insert', (req, res, next) => {
  const values = req.body;

  pool.query(`INSERT INTO student SET ?`, [values], (err, result) => {
    if (err) {
      err = new Error('Not Connected');
      next(err);
    } else {
      res.status(201).json({ msg: `added ${result.insertId}` });
      console.log(result);
    }
  });
});

index.spec.js:

const routes = {};
jest.mock('express', () => {
  const mExpress = {
    post: jest.fn((path, controller) => {
      routes[path] = controller;
    })
  };
  return jest.fn(() => mExpress);
});

let queryCallback;
jest.mock('pg', () => {
  const mpool = {
    query: jest.fn((query, values, callback) => {
      queryCallback = callback;
    })
  };
  const mPool = jest.fn(() => mpool);
  return { Pool: mPool };
});

require('./index');
const express = require('express');
const { Pool } = require('pg');
const app = express();
const pool = new Pool();

describe('insert', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should insert data correctly', done => {
    const logSpy = jest.spyOn(console, 'log');
    expect(app.post).toBeCalledWith('/insert', expect.any(Function));
    const mReq = { body: 1 };
    const mRes = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis() };
    routes['/insert'](mReq, mRes);
    expect(pool.query).toBeCalledWith('INSERT INTO student SET ?', [1], expect.any(Function));
    const mResult = { insertId: 1 };
    queryCallback(null, mResult);
    expect(mRes.status).toBeCalledWith(201);
    expect(mRes.status().json).toBeCalledWith({ msg: 'added 1' });
    expect(logSpy).toBeCalledWith(mResult);
    done();
  });

  test('should call error handler middleware', () => {
    expect(app.post).toBeCalledWith('/insert', expect.any(Function));
    const mReq = { body: 1 };
    const mRes = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis() };
    const mNext = jest.fn();
    routes['/insert'](mReq, mRes, mNext);
    expect(pool.query).toBeCalledWith('INSERT INTO student SET ?', [1], expect.any(Function));
    const mError = new Error('network error');
    queryCallback(mError, null);
    expect(mNext).toBeCalledWith(new Error('Not Connected'));
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/56635460/index.spec.js (7.391s)
  insert
    ✓ should insert data correctly (15ms)
    ✓ should call error handler middleware (1ms)

  console.log node_modules/jest-mock/build/index.js:860
    { insertId: 1 }

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.js |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        8.571s

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

Lin Du
  • 88,126
  • 95
  • 281
  • 483