chai and mocha showing test successful after error - node.js

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)

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 });
}

Related

Make mocha test fail in try / catch

I have the following function to validate a JSON file:
export const validateJSON = (sourceDir, fileName) => {
return new Promise((resolve, reject) => {
try {
pricingService.processJSON(params, data)
.then(data => {
config.accounts.currencies.forEach(function (currency) {
if (data[currency] === '' || data[currency] === undefined) {
reject({err: 'Missing required values'});
}
});
resolve('JSON Validation Success');
})
.catch(error => {
logger.error({
message: `Error while processing JSON, request Failed with Error: ${error}`,
});
reject({err: error});
});
}
} catch (error) {
logger.error({
message: `Error while validating JSON file, request Failed with Error: ${error}`,
});
return reject({err: {status: 422, message: 'Error while validating JSON - Unprocessable Entity'}});
}
});
};
Now, I have a test in Mocha
it.only('Validate Pricing JSON file', function () {
s3Service.validateJSON('',filename,Date.now()).then(data =>{
setTimeout(() =>{
assert.equal(data, 'JSON Validation Success')
done()
}, 1000)
}).catch(function (error) {
console.error("JSON validation failed "+JSON.stringify(error))
throw error
})
});
What I am trying to do is to validate the JSON file in the test and if there is some fields are missing in the file, the test should fail. Now when I execute the test with a file with missing entries, I am getting the following error printed to console.
JSON validation failed {"err":{"status":422,"message":"Error while validating JSON - Unprocessable Entity"}}
(node:26091) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): #<Object>
(node:26091) [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.
But the test is shown as passed. How can I make it fail if there is an error ? Also how to get rid of the UnhandledPromiseRejectionWarning ? I am very new to Unit Testing and so any help will be appreciated.
Don't throw an error.
Use assert.fail
Check this

Why am I having trouble displaying and deleting in Mongo using Prisma (React app)?

I use Node, Express, React, Mongo and Prisma to import a csv file in the database, display it on the frontend and delete all records in the db. It worked with one record and so I assumed it would work with the rest of the csv file (1000 records). But I get an error:
Invalid `prisma.movie.findMany()` invocation:
Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawError { code: "unknown", message: "Command failed (CursorNotFound): cursor id 124425195753416376 not found)" } })
(node:2171) UnhandledPromiseRejectionWarning: Error:
Invalid `prisma.movie.deleteMany()` invocation:
Error occurred during query execution:
ConnectorError(ConnectorError { user_facing_error: None, kind: RawError { code: "unknown", message: "Command failed (CursorNotFound): cursor id 4391617472265441923 not found)" } })
at cb (/Users/nwsursock/Sites/test-algot/backend/node_modules/#prisma/client/runtime/index.js:36378:17)
at runMicrotasks ()
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async exports.deleteRequest (/Users/nwsursock/Sites/test-algot/backend/src/controllers/movie.controller.js:49:3)
(node:2171) 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: 2)
My code is rather simple. I'm using the Prisma API in REST endpoints.
const { PrismaClient } = require("#prisma/client");
const prisma = new PrismaClient();
exports.createRequest = async (req, res) => {
const movie = req.body.movie;
console.log("============> importing", movie);
const data = {
name: movie.Name,
genre: movie.Genre,
descr: movie.Description,
director: movie.Director,
actors: movie.Actors,
year: movie.Year,
runtime: Number(movie["Runtime (Minutes)"]),
rating: Number(movie.Rating),
votes: Number(movie.Votes),
revenue: Number(movie["Revenue (Millions)"]),
score: Number(movie.Metascore),
};
const result = await prisma.movie.create({ data });
console.log("============> imported", result);
res.status(201).json({ message: "Movie correctly added!" });
};
exports.readRequest = async (req, res) => {
try {
const movies = await prisma.movie.findMany();
res.status(200).json(movies);
} catch (e) {
console.log("======> Error:", e.message);
}
};
exports.deleteRequest = async (req, res) => {
await prisma.movie.deleteMany({});
res.status(202).json({ message: "Table deleted!" });
};
It's a version problem. You have to downgrade to Prisma 2.26. Above, the bug appears. https://github.com/prisma/prisma/issues/8389

Express is res.sending both success and error - ERR_HTTP_HEADERS_SENT

I have strange problem with [ERR_HTTP_HEADERS_SENT]: : Cannot set headers after they are sent to the client. It's in try/catch, but still somehow after res.send({message: 'Company set up'}) it also sends res.send({error}) which shouldn't occur.
I also tried return res.send({message: 'Company set up'}), but I have still same error. Along with that error I also get:
(node:19234) 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(). (rejection id: 1).
What I found that there is no problem when await knex() calls are commented out.
try {
if (req.files) { //multer
let data = req.body
const locations = JSON.parse(data.locations)
const parsedLocations = locations.map((obj, index) => {
(...)
})
await asyncForEach(parsedLocations, async (element, index) => {
const country = await knex('countries').first().where({ country: element.country })
})
console.log('company set up')
res.send({ message: 'Company set up' })
}
} catch (error) {
console.log('error')
console.log(error)
res.send({ error})
}
Here's the asyncForEach function for reference:
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
Error log from Node.js:
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:267:15)
at ServerResponse.send (/Users/xx/Developer/microservice/node_modules/express/lib/response.js:158:21)
at router.post (/Users/xx/Developer/microservice/routes/admin.js:714:11)
(node:19337) 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(). (rejection id: 3)
This error is due to trying to send multiple response.
You can check if response has been already sent or not before returning response.
Like:
if (res.headerSent) {
res.send({ data/ error})
If already sent, then it will not send another.
Your code is not catching the error.
return res.status(405).send('User already exist');

Mock fetch in Jest tests throwing “invalid json response” and “Unhandled promise rejection” errors

I’m trying to do unit tests for some of my redux-saga generators and am getting a couple of errors I’m not sure how to resolve. I’m using create-react-app, so my testing suite is Jest and Enzyme.
A basic example:
Setup: src/setupTests.js
import 'jest-enzyme'
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
global.fetch = require('jest-fetch-mock')
configure({
adapter: new Adapter(),
automock: false,
collectCoverageFrom: [
'<rootDir>/src/**/*.js',
'!<rootDir>/src/**/*.stories.js',
'!<rootDir>/node_modules/',
'!<rootDir>/src/index.js',
],
coverageThreshold: {
global: {
branches: 90,
functions: 90,
lines: 90,
statements: 90,
},
},
verbose: true,
})
Saga: src/store/sagas/api-saga.js
import { takeEvery, put } from 'redux-saga/effects'
import {
API_ERRORED,
DATA_LOADED,
DATA_REQUESTED,
} from '../constants/action-types'
export function* workerSaga() {
try {
const payload =
yield fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
yield put({
type: DATA_LOADED,
payload,
})
} catch (e) {
yield put({
type: API_ERRORED,
payload: false,
})
}
}
export default function* watcherSaga() {
yield takeEvery(
DATA_REQUESTED,
workerSaga,
)
}
Saga Test: src/store/sagas/api-saga.test.js
import { put, takeEvery } from 'redux-saga/effects'
import watcherSaga, { workerSaga } from './api-saga'
import {
API_ERRORED,
DATA_LOADED,
DATA_REQUESTED,
} from '../constants/action-types'
describe('saga workers', () => {
test('should dispatch action "DATA_LOADED" with result from fetch API',
() => {
const articles = 'Some content'
const mockResponse = {
articles,
}
const generator = workerSaga()
generator.next()
expect(generator.next(mockResponse).value)
.toEqual(
put({
type: DATA_LOADED,
payload: {
articles,
},
})
)
expect(generator.next().done).toBeTruthy()
})
})
The errors I’m receiving:
(node:2009) UnhandledPromiseRejectionWarning: FetchError: invalid json response body at undefined reason: Unexpected end of JSON input
(node:2009) 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(). (rejection id: 2)
(node:2009) [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.
(node:2009) UnhandledPromiseRejectionWarning: FetchError: invalid json response body at undefined reason: Unexpected end of JSON input
(node:2009) 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(). (rejection id: 4)
I thought introducing jest-fetch-mock would help resolve some of these issues, but it doesn’t seem so. The tests pass, but these errors persist.
What am I missing?
Versions
redux#4.0.4
redux-saga#1.0.5
enzyme#3.10.0
jest#24.7.1
You'll need to set up jest-fetch-mock to return a value:
Something like:
describe('saga workers', () => {
test('should dispatch action "DATA_LOADED" with result from fetch API',
() => {
const articles = 'Some content'
const mockResponse = {
articles,
}
// configure the mockResponse here:
fetch.mockResponse(mockResponse);
const generator = workerSaga()
generator.next()
expect(generator.next().value)
.toEqual(
put({
type: DATA_LOADED,
payload: {
articles,
},
})
)
expect(generator.next().done).toBeTruthy()
})
})
See https://github.com/jefflau/jest-fetch-mock#api

how can i parse a error message that i am getting in nodejs app

I am making an app with reactjs frontend and nodejs backend api for that at someplace i getting error something like this.
But here i want to get only this message email: {message: "This email is already taken", I tried to parse this error using some online turorial but when i try them i get error from backend.
This is the error after using errorparser
(node:14208) UnhandledPromiseRejectionWarning: ReferenceError: errors is not defined
at exports.default (C:/projects/bookworm-practice/bookworm-api/src/utils/parseErrors.js:5:15)
at C:/projects/bookworm-practice/bookworm-api/src/routes/users.js:14:54
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:14208) 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(). (rejection id: 1)
(node:14208) [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.
this is my parseError function
import _ from 'lodash';
export default function () {
const result = {};
_.forEach(errors, (val, key) => {
result[key] = val.message;
});
return result;
}
this is my user function where i am using parseError
import express from 'express';
import User from '../models/User';
import parseErrors from '../utils/parseErrors';
const router = express.Router();
router.post('/', (req, res) => {
const { email, password } = req.body.user;
const user = new User({ email });
user.setPassword(password);
user.save()
.then(user => res.json({ user: user.toAuthJSON() }))
//.catch(err => res.json({ err })); // this is the default one
.catch(err => res.status(400).json({ errors: parseErrors(err.errors)
//this is after adding parseErrors funtion
}))
})
export default router;
Your parseErrors function did not includes errors as argument
import _ from 'lodash';
export default function (errors) {
const result = {};
_.forEach(errors, (val, key) => {
result[key] = val.message;
});
return result;
}

Resources