Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

expressJS/jestJS: How to split get() function to write simple jest unit test?

How do I define a get() routing in an expressJS application with the intention of doing easy unit testing?

So as a first step I moved the function of get() in an own file:

index.js

const express = require('express')
const socketIo = require('socket.io')
const Gpio = require('pigpio').Gpio

const app = express()
const server = http.createServer(app)
const io = socketIo(server)

const setStatus = require('./lib/setStatus.js')

app.locals['target1'] = new Gpio(1, { mode: Gpio.OUTPUT })

app.get('/set-status', setStatus(app, io))

lib/setStatus.js

const getStatus = require('./getStatus.js')

module.exports = (app, io) => {
  return (req, res) => {
    const { id, value } = req.query // id is in this example '1'
    req.app.locals['target' + id].pwmWrite(value))
    getStatus(app, io)
    res.send({ value }) // don't need this
  }
}

lib/getStatus.js

const pins = require('../config.js').pins

module.exports = async (app, socket) => {
  const res = []
  pins.map((p, index) => {
    res.push(app.locals['target' + (index + 1)].getPwmDutyCycle())
  })
  socket.emit('gpioStatus', res)
}

So first of all I'm not quite sure, if I split that code correctly - thinking of doing unit testing.

For me the only thing which has to be done by calling /set-status?id=1&value=50 is to call pwmWrite() for an (I guess) object, which is defined by new Gpio and stored in locals of expressJS.

And for the second: If this should be the correct way, I do not understand how to write a jestJS unit test to check if pwmWrite has been called - which is inside of an asyncronous function.

This is my attempt, but I can't test for the inside call of pwmWrite:

test('should call pwmWrite() and getStatus()', async () => {
  const app = {}
  const io = { emit: jest.fn() }
  const req = {
    app: {
      locals: {
        target1: { pwmWrite: jest.fn() }
        }
      }
    }
  }
  expect.assertions(1)
  expect(req.app.locals.target1.pwmWrite).toHaveBeenCalled()
  await expect(getStatus(app, io)).toHaveBeenCalled()
})
like image 946
user3142695 Avatar asked Oct 29 '22 02:10

user3142695


1 Answers

You are very close, just missing a few things.

You need to call the methods setStatus and getStatus before the expect statements, and you were missing mocks on req.query and res, since getStatus uses them.

test('should call pwmWrite() and getStatus()', async () => {
  const app = {}
  const io = {};
  const req = {
    query: {
      id: '1',
      name: 'foo'
    },
    app: {
      locals: {
          target1: { pwmWrite: jest.fn() }
      }
    }
  };
  const res = { send: jest.fn() };

  // Mock getStatus BEFORE requiring setStatus
  jest.mock('./getStatus');

  //OBS Use your correct module paths
  const setStatus = require('./setStatus');
  const getStatus = require('./getStatus');


  // Call methods
  setStatus(app, io)(req, res);

  expect.assertions(2);

  // Get called in setStatus
  expect(req.app.locals.target1.pwmWrite).toHaveBeenCalled();

  // See if mocked getStatus has been called
  await expect(getStatus).toHaveBeenCalled();
});

The getStatus needs to be mocked before requiring setStatus, since its used there

like image 56
lazreg87 Avatar answered Nov 09 '22 09:11

lazreg87