node.jschaisinonstubbingsinon-chai

Sinon stub is calling actual function instead of stubbing


I have simple express app in which I'm trying to add test cases for GET route. Somehow the sinon stubbing is not actually working as expected. Below is my code for reference, This is my app.js

require("dotenv").config()
const express = require("express");
const app = express();
app.use(express.json());
const indexController = require('../src/controller/index');
const { verifyRequest } = require("./lib/Middleware")

app.use(verifyRequest, async (req, res, next) => {
    next()
})

app.get('/test', indexController.getData);

const port = parseInt(process.env.PORT) || 8080;

app.listen(port, async function () {
    console.log("Server started");
});

module.exports = app;

This is my middleware,

var { findOne } = require("../model/user.model");

const verifyRequest = async (req, res, next) => {
  try {
      let credentials = Buffer.from(req.headers.authorization.split(" ")[1], 'base64').toString().split(':');
      const data = await findOne(credentials[0], credentials[1])
      console.log(data)
      let allowed;
      if (!data) {
        return res.status(404).send({
          error: "User not found",
        });
      }
      next();
      return true;
    }
  } catch (error) {
    return res.status(500).send({
      error: error.message,
    });
  }
};

module.exports = {
  verifyRequest,
};

Below is my DB model,

const { Sequelize, DataTypes } = require("sequelize");
const sequelize = new Sequelize("db_name", "postgres", "****", {
  host: "****",
  port: 5432,
  dialect: "postgres",
  define: {
    defaultScope: {
      attributes: { exclude: ["createdAt", "updatedAt"] },
    },
    timestamps: false,
  },
});
sequelize
  .authenticate()
  .then(() => {
    console.log("DB connection has been established successfully.");
  })
  .catch((error) => {
    console.error("Unable to connect to the database: ", error);
  });

const User = sequelize.define("users", {
  email: {
    type: Sequelize.STRING,
  },
  password: {
    type: Sequelize.STRING,
  },
  family: {
    type: Sequelize.STRING,
  },
  active: {
    type: Sequelize.BOOLEAN,
  },
});

const findOne = async (email, password) => {
  return await User.findOne({
    where: {
      email,
      password,
    },
  });
}

module.exports = { User, sequelize, findOne };

Below is handler function,

const getData = async (req, res) => {
    try {
        console.log('Inside actual handler')
        res.send({
            code: 200,
            data: 'Response from get data'
        });
    } catch (error) {
        res.status(500).send({
            code: 500,
            error: error.message
        });
    }
};

module.exports = getData;

And my test case is,

process.env.NODE_ENV = "test";
let expect  = require('chai').expect;
let app = require('../../app')
var request = require('supertest');
var sinon = require('sinon');
let User = require('../../model/user.model')

let auth = 'Basic ' + Buffer.from("Test:Test").toString('base64')
let userStub;
describe('Get data controller', async function() {
    before(() => {
        userStub = sinon.stub(User, 'findOne');
    })
    
    it('should respond with JSON', function(done) {
        userStub.resolves({username: 'Test', password: 'Test', family: 'admin'});
        request(app)
            .get('/test/')
            .set("Authorization", auth)
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function(err, res) {
            if (err) return done(err);
            expect(res.body).to.be.an('Object');
            done();
            });
    }).timeout(10000);
    after(() => {
        userStub.restore();
    });
});

In this cod, I'm trying to stub the findOne method but when I try to run the test case it actually calls the method instead of stubbing it. Hence I'm getting 404 instead of 200. Any help here would be appriciated


Solution

  • I needed to change the findOne import and method call inside middleware from,

    var { findOne } = require("../model/user.model");
    

    to

    var model = require("../model/user.model");
    const data = await model.findOne(credentials[0], credentials[1])