express-deliver
Version:
API json responses done easy
371 lines (324 loc) • 9.39 kB
JavaScript
const expressDeliver = require('..')
const expect = require('chai').expect
const express = require('express')
const request = require('supertest')
const ExceptionPool = expressDeliver.ExceptionPool
function testCtrl(ctrl,statusCode,body,done,exceptionPool){
let app = express()
expressDeliver(app,{
exceptionPool,
printInternalErrorData:true
})
app.get('/',ctrl)
expressDeliver.errorHandler(app)
let test = function(err,res){
expect(res.status).to.be.equal(statusCode)
expect(res.body).to.be.deep.equal(body)
done()
}
if (typeof statusCode == 'function')
test = statusCode
request(app).get('/').end(test)
}
//Check for async support
let m = process.version.match(/v(\d+).(\d+)/ )
let vMajor = m && m[1]
let vMinor = m && m[2]
let supportsAsync = vMajor>=8 || (vMajor==7 && vMinor >= 6)
describe('controller async',()=>{
it('should respond normally',(done)=>{
testCtrl((req,res)=>{
res.send('hi')
},(err,res)=>{
expect(res.text).to.be.equal('hi')
done()
})
})
it('should deliver success',(done)=>{
testCtrl(function*(){
return 'hi'
},200,{
status:true,
data:'hi'
},done)
})
if (supportsAsync){
//If called normally throws error in <7.6
eval(`
it('should deliver success with async function',(done)=>{
testCtrl(async function(){
return await Promise.resolve('hi')
},200,{
status:true,
data:'hi'
},done)
})
`)
}
it('should deliver success from promise',(done)=>{
testCtrl(function test1Deliver(){
return Promise.resolve('hi')
},200,{
status:true,
data:'hi'
},done)
})
it('should deliver fail',(done)=>{
testCtrl(function*(){
throw new Error('foo')
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: foo'
}
},done)
})
it('should deliver custom exception',(done)=>{
testCtrl(function*(req,res){
throw new res.exception.CustomError()
},403,{
status:false,
error:{
code:4000,
message:'This is a custom error'
}
},done, new ExceptionPool({
CustomError:{
code: 4000,
statusCode: 403,
message: 'This is a custom error',
}
}))
})
it('should deliver converted custom exception',(done)=>{
testCtrl(function*(){
throw new Error('Custom message match')
},403,{
status:false,
error:{
code:4001,
message:'This is a custom converted error'
}
},done,new ExceptionPool({
CustomConvertedError:{
code: 4001,
statusCode: 403,
message: 'This is a custom converted error',
conversion: err => err.message=='Custom message match'
}
}))
})
it('should deliver 500 with offlimit statusCode',(done)=>{
testCtrl(function*(req,res){
throw new res.exception.CustomStatusCode()
},500,{
status:false,
error:{
code:4002,
message:'This is a custom error'
}
},done,new ExceptionPool({
CustomStatusCode:{
code: 4002,
statusCode: 200,
message: 'This is a custom error'
}
}))
})
it('should deliver 404 with empty next',(done)=>{
testCtrl(function*(req,res,next){
next()
},404,{
status:false,
error:{
code:1002,
message:'Route not found'
}
},done)
})
it('should ignore promise result',(done)=>{
testCtrl(function*(req,res,next){
next('ignore')
res.status(201)
res.send({message:'hi'})
},201,{
message:'hi'
},done)
})
it('should deliver fail with async error',(done)=>{
testCtrl(function(){
setTimeout(()=>{
throw new Error('async')
})
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: async'
}
},done)
})
it('should deliver fail calling next with value and ignore promise rejection',(done)=>{
testCtrl(function*(req,res,next){
next('something')
throw 'shit'
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: something'
}
},done)
})
it('should deliver from promise',(done)=>{
testCtrl(function*(){
return yield Promise.resolve('from promise')
},200,{
status:true,
data:'from promise'
},done)
})
it('should deliver custom response data',(done)=>{
testCtrl(function*(req,res){
return new res.ResponseData({
paginated:true
})
},200,{
status:true,
paginated:true
},done)
})
it('should deliver custom response data without status',(done)=>{
testCtrl(function*(req,res){
return new res.ResponseData({clean:true},{appendStatus:false})
},200,{clean:true},done)
})
it('should deliver non-object response data with status',(done)=>{
testCtrl(function*(req,res){
return new res.ResponseData('algo',{appendStatus:true})
},200,{status:true},done)
})
it('should deliver normal error',(done)=>{
testCtrl(()=>{
throw 'something'
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: something'
}
},done)
})
it('should deliver syntax error',(done)=>{
testCtrl(function*(){
//eslint-disable-next-line
foo()
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'ReferenceError: foo is not defined'
}
},done)
})
it('should avoid headers sent',(done)=>{
testCtrl(function*(req,res){
res.send({custom:'first'})
return 'second'
},200,{custom:'first'},done)
})
it('should avoid circular JSON',(done)=>{
testCtrl(function*(){
let a = {}
a.self = a
return a
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'TypeError: Converting circular structure to JSON'
}
},done)
})
it('should use res.locals as context',(done)=>{
let app = express()
expressDeliver(app)
app.get('/',function(req,res,next){
res.locals.signal = 1
next()
},function*(){
return this.signal
})
expressDeliver.errorHandler(app)
request(app).get('/').end(function(err,res){
expect(res.body).to.be.deep.equal({
status:true,
data:1
})
done()
})
})
})
describe('controller sync',()=>{
it('should deliver success',(done)=>{
testCtrl(function test2DeliverSync(){
return 'hi'
},200,{
status:true,
data:'hi'
},done)
})
it('should ignore promise result',(done)=>{
testCtrl(function test3DeliverSync(req,res,next){
next('ignore')
res.status(201)
res.send({message:'hi'})
},201,{
message:'hi'
},done)
})
it('should deliver 404 with empty next',(done)=>{
testCtrl(function test4DeliverSync(req,res,next){
next()
},404,{
status:false,
error:{
code:1002,
message:'Route not found'
}
},done)
})
it('should deliver fail',(done)=>{
testCtrl(function test5DeliverSync(){
throw new Error('foo')
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: foo'
}
},done)
})
it('should deliver fail calling next with value and ignore error thrown',(done)=>{
testCtrl(function test6DeliverSync(req,res,next){
next('something')
throw 'shit'
},500,{
status:false,
error:{
code:1000,
message:'Internal error',
data:'Error: something'
}
},done)
})
})