Bcrypt.compare function working in code but not functioning in chai/mocha tests

I have integrated node.js backend into my project. For encrypting passwords, I am utilizing the bcrypt library. To compare the string password from the request with the hashed password in the database, I am using the bcrypt.compare function. The bcrypt.compare function is functioning properly in my code as it has been manually tested with Postman and works seamlessly in production. However, when conducting tests with chai-http and mocha, it encounters a hang-up.

In my testing process, I utilize mocha with chai-http to initiate an HTTP POST request:

describe('Testing login', () => {
  it('should return status 200 when there is a user in the DB with the correct password', (done) => {
    chai.request(server)
    .post('/login')
    .send({
      login: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d6a2b3a5a296a2b3a5a2f8a2b3a5a2">[email protected]</a>',
      password: 'somepassword'
    })
    .end((err, res) => {
      res.should.have.status(200)
      done()
    })
  })
})

The controller's bcrypt function is outlined below:

async function auth(req, res) {
  let { login, password } = req.body
  try {
    let payload = {}
    let result = {}
    await
    User.findOne({ where: { userEmail: login } }).then(user => {      
      return result = user
    })
    bcrypt.compare(password, result.dataValues.password, await function (err, data) {
      if (err) {        
        throw Error(err)
      }
      if (result && data) {       
        payload.isAdmin = result.dataValues.isAdmin
        payload.ID = result.dataValues.id
        let token = jwt.sign(payload, 'yoursecret')
        res.status(200).send({ token: token })
      } else { res.status(401) }
    })
  } catch (error) {
    res.sendStatus(500)
  }
}

Is there a recommended approach for testing this function?

Additional information:
mocha version 5.2.0 - global and local
node v8.11.4
Windows 10 x64

"devDependencies": {
  "@types/chai-as-promised": "^7.1.0",
  "chai": "^4.1.2",
  "chai-as-promised": "^7.1.1",
  "chai-http": "^4.2.0",
  "eslint": "^5.5.0",
  "eslint-config-standard": "^12.0.0",
  "eslint-plugin-import": "^2.14.0",
  "eslint-plugin-node": "^7.0.1",
  "eslint-plugin-promise": "^4.0.1",
  "eslint-plugin-standard": "^4.0.0",
  "express-unit": "^2.1.1",
  "mocha": "^5.2.0",
  "mock-express-request": "^0.2.2",
  "mock-express-response": "^0.2.2",
  "nyc": "^13.0.1",
  "proxyquire": "^2.1.0",
  "sinon": "^6.2.0",
  "supertest": "^3.3.0",
  "ws": "3.3.2"
}

Answer №1

The issue was not related to chai, mocha, or bcrypt. It stemmed from the following code snippet:

    } else {
        res.status(401)
    }

The correct code should be:

    } else {
        res.status(401).send(something)
    }

Alternatively, you can use:

    } else {
        res.sendStatus(401)
    }

I believe Express expects a .send() method call after .status(), causing the connection to hang without a response.

Answer №2

I see a few issues here and some possible solutions to explore. It seems like the problem does not lie with chai-http.

For further reference, you may want to check out the following resources: MDN's guide on async/await functions
Using Promises with bcrypt

Here is an adjusted version of your route handler:

async function auth(req, res) {
    let {
        login,
        password
    } = req.body
    try {
        let payload = {}
        let result = await User.findOne({
            where: {
                userEmail: login
            }
        });
        const data = await bcrypt.compare(password, result.dataValues.password);

        if (result && data) {
            payload.isAdmin = result.dataValues.isAdmin
            payload.ID = result.dataValues.id
            let token = jwt.sign(payload, 'yoursecret')
            res.status(200).send({
                token: token
            })
        } else {
            res.sendStatus(401)
        }
    } catch (error) {
        res.sendStatus(500)
    }
}

If you're having trouble with setting up your routes, be cautious about handling async functions properly. Check out this resource for more information: how to use express with async/await in Node 8

I hope this helps. Additionally, it would be beneficial to know how you are initializing routes and the versions of Node, Express, chai-http, bcrypt, and jsonwebtoken you are using.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Efficiently refresh several DIV elements with a single JSON request

After extensive searching, I've come to the conclusion that due to my limited proficiency in javascript, I need some help. The issue at hand is with a json format output produced by an ASP page on a separate webserver, which looks something like this: ...

Swap out the HTML tags with JavaScript code

I've been looking everywhere, but I couldn't find the answer. Here is my issue / question: I have a page from CKEDITOR with: var oldText = CKEDITOR.instances.message.getData(); So far, so good. The string looks something like this: <table ...

Using Postman for JSONSchema validation

Recently, I developed a web API using node.js and express.js. As part of the process, I wanted to ensure that the JSON data coming into my application adhered to a specific schema. The exact schema I am working with is as follows: var schema = { "$schema ...

Exploring the Ins and Outs of Transition Testing in D3 v4

Previously, in older versions of D3, you were able to create unit tests that checked the state of a D3 component after all transitions had finished by flushing the timer with d3.timer.flush(). However, in D3 version 4, this has changed to d3.timerFlush(), ...

Unable to find the desired match with Regex

I'm attempting to use a regex to replace content within brackets, but I'm encountering an unexpected result. This is the text I'm trying to target: Foo (bar) Below is the regex pattern I am using: /(?=\().*(?=\))/ My expectati ...

The tweet button is not displaying correctly on the website

Visit my website here, where I have integrated a tweet button generated from Twitter.com. It was working fine for the initial few posts, but now it is failing to load and only displaying text. I have checked the console for any JavaScript errors, but so f ...

Error: The function isInitial of chunk cannot be found

Currently, I am attempting to build my program using the following command: "build": "NODE_ENV='production' webpack -p", However, I encountered an error message: node_modules/extract-text-webpack-plugin/index.js:267 var shouldE ...

How can I get the class name of the drop destination with react-dnd?

Imagine having this component that serves as a drop target module. import { useDrop } from 'react-dnd'; import './css/DraggableGameSlot.css'; type DraggableGameSlotProps = { className: string, text: string } function Draggable ...

Specialized Node.js extension for automatic dependency installation

My current setup involves a custom Yeoman generator for specific applications, which comes with its own set of dependencies and configurations. - GruntJS must be installed globally; - Bower must be installed globally; - Yeoman must be installed globally ...

How can we integrate this icon/font plugin in CSS/JavaScript?

Check out the live demonstration on Jsfiddle http://jsfiddle.net/hc046u9u/ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materializ ...

Hover to stop menu movement

Can someone help me achieve a similar menu hover effect like this one? I'm trying to create a menu with a hold/pause effect on hover, specifically in the section titled "A programme for every vision". The goal is to navigate through the sub menus smo ...

The click listener triggers a single time when a render method is nested within it

When I have a click listener on a button that resets the innerHTML of a div with a render method, the listener fires every time I click if I take out the render function. However, if the render function is included, the listener does not fire multiple time ...

The message "ERR_HTTP_HEADERS_SENT" indicates that the headers have already been sent to the client and cannot be set again

I am in the process of developing a straightforward REST API using NodeJS and Express without utilizing any database. My data is being stored in JSON files, structured as an array of objects. My routes include fund-name/:portId Here's the code snipp ...

"Step-by-step guide on assigning a class to a Component that has been

When attempting to pass a component as a prop of another component, it functions correctly. However, when I try to pass a Component and manage its CSS classes within the children, I find myself stuck. I am envisioning something like this: import Navbar fr ...

What is the best way to integrate a VueJS application into an already established web page?

Working on a project involves fixing issues with legacy components in a server-rendered web page. I proposed rewriting these parts in Vue to facilitate our migration, and the team approved. I created a mini-app using the Webpack template from Vue CLI, whi ...

Issue uploading with Candy Machine Version 2/ complications with directory

For some reason, I am encountering issues with the upload operation. Switching from relative to absolute paths did not resolve the error, and using the -c flag for the directory containing images and JSON files is causing a problem. However, other flags ...

The MySQL node is throwing an error stating that headers cannot be modified after they have already been sent

I am currently working on a project that involves fetching a list of movies from a directory, extracting titles, retrieving movie information from TMDB, checking if the movie information is stored in a mysql database, and if not, inserting the information ...

Both if and else statements are carrying out code in JavaScript/jQuery

The second if statement is functioning correctly, but the first one always triggers the else statement and never stands alone. This jQuery function is enclosed within another function that is invoked under the "$(document).ready" command. I resorted to u ...

Filtering data in an antd table by searching

Just starting out with React hooks, specifically using TypeScript, and I'm struggling to implement a search filter with two parameters. Currently, the search filter is only working with one parameter which is 'receiver?.name?'. However, I wo ...

Launch in a new window using JavaScript

Check out my interactive map here. Currently, when I click on different sections of the map, the target page opens in the same window. However, I would like it to open in a new window instead. <iframe src="http://bluewingholidays.com/map/map.html ...