Yatin Gaikwad
Yatin Gaikwad

Reputation: 1200

chai and mocha showing test successful after error

I am using chai and mocha to test my REST API developed in NodeJS with typescript. I have written my test cases with mockgoose library to mock mongo db. When I run the first test case it successfully adds some data in database, but when I run the second and third test case it first shows Cannot set headers after they are sent to the client and later shows that the test is passed. I am not getting this workflow of execution how is it happening. Could anyone please explain. My test case file looks like this :

process.env.NODE_ENV = 'TEST';

import { expect } from 'chai';
import request from 'supertest';

import app from '../app';
import * as mongodb from '../mongo/connection';

describe('Testing the API', () => {

    before((done) => {
        mongodb.connectMock()
            .then(() => done())
            .catch((err:any) => done(err))
    })

    it('OK, adding new employee', (done) => {
        request(app).put('/add')
            .send(<some JSON data>)
            .then(res => {
                ...some matcher
                done();
            })
            .catch(err => done(err));
    })

   it('OK, getting all employees', (done) => {
        request(app).get('/all')
            .then(res => {
                ...some matcher
                done();
            })
            .catch(err => { 
                done(err)
            });
    })

   it('OK, getting employee by ID', (done) => {

        request(app)
            .get(`/create/${id}`)
            .then(res => {
                ...some matcher
                done();
            })
            .catch(err => done(err));
    }) 
})

and the controller file that produces the error is :

import { Request, Response } from 'express';
import Employee from '../models/Employee'
import { v4 as uuidv4 } from 'uuid';

export let allEmployee = (req: Request, res: Response) => {
    Employee.find({})
            .then(allEmployee => {
                console.log('Getting all employee');
                if(allEmployee.length > 0)
                    res.status(200).json(allEmployee);
                console.log('Empty set of employees, please create');
                res.status(404).json({ error: 'No employee found, please create', employee: allEmployee });
            })
            .catch((err:any) => {
                console.log(err)
                res.status(400).json({ error: err }); ****** I GET THE ERROR HERE ******
            })
}

export let getEmployeeById = (req: Request, res: Response) => {
    const employeeId: string = req.params.id;
    Employee.find({ employeeId: employeeId })
            .then(employee => {
                console.log(`Getting employee with employee ID: ${employeeId}`);
                if(employee.length > 0)
                    res.status(200).json(employee);
                console.log(`No employee with employee ID: ${employeeId} found`);
                res.status(404).json({ error: 'No employee found', employee: employee });
            })
            .catch(err => {
                res.status(400).json({ error: err }); ****** I GET THE ERROR HERE ******
            })
}

export let addEmployee = (req: Request, res: Response) => {

    let employee = new Employee(<Some employee data in JSON>)

    employee.save()
            .then(employeeSaved => {
                res.status(201).json({ message: 'New employee created!', employee: employeeSaved });
            })
            .catch(err => {
                res.status(400).json({error:err}); 
            })
}

The first test case that adds the employee to database works perfectly fine but when it does for second and third test case it shows error first and then successfully passes the test case. It looks like :

Mock MongoDB Connected
    ✓ OK, adding new employee (69ms)
Getting all employees
Empty set of employees, please create
(node:16761) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:526:11)
    at ServerResponse.header (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:771:10
)
    at ServerResponse.send (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:267:15)
    at /Users/abc/Downloads/some/git-test/some/Docker_Solution/src/controllers/employeeController.ts:16:33
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:16761) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch bl
ock, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rej
ections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 9)
(node:16761) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
    ✓ OK, getting all employees
Getting employee with employee ID: 2b1e419e-57a7-4785-a3d7-96a1c786676b
No employee with employee ID: 2b1e419e-57a7-4785-a3d7-96a1c786676b found
(node:16761) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:526:11)
    at ServerResponse.header (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:771:10)
    at ServerResponse.send (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/Users/abc/Downloads/some/git-test/some/Docker_Solution/node_modules/express/lib/response.js:267:15)
    at /Users/abc/Downloads/some/git-test/some/Docker_Solution/src/controllers/employeeController.ts:31:33
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:16761) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 10)
    ✓ OK, getting employee by ID


  3 passing (1s)

Upvotes: 0

Views: 877

Answers (1)

Andrew Nolan
Andrew Nolan

Reputation: 2107

Your problem seems to be your if conditions for res.status(200) or res.status(400) in both of your routes you have an issue with.

if(employee.length > 0)
   res.status(200).json(employee);
   console.log(`No employee with employee ID: ${employeeId} found`);
   res.status(404).json({ error: 'No employee found', employee: employee });

should be and if(){} else{} because you are trying to send/alter the response again along with the 200 you already send

if(employee.length > 0) {
    res.status(200).json(employee);
} else {
    console.log(`No employee with employee ID: ${employeeId} found`);
    res.status(404).json({ error: 'No employee found', employee: employee });
}

Upvotes: 1

Related Questions