572 lines
20 KiB
JavaScript
572 lines
20 KiB
JavaScript
import { Eltro as t, spy, assert, stub} from 'eltro'
|
|
import { FileResponse, Flaska, FlaskaRouter } from '../flaska.mjs'
|
|
import { fakeHttp, createCtx } from './helper.mjs'
|
|
|
|
const fakerHttp = fakeHttp()
|
|
const fakeStream = { pipeline: spy() }
|
|
|
|
t.describe('#requestEnd()', function() {
|
|
t.test('calls onerror correctly on error', function(cb) {
|
|
const assertError = new Error('test')
|
|
const assertBody = { a: 1 }
|
|
const assertStatus = 501
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 7
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'application/json; charset=utf-8')
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength)
|
|
assert.ok(body)
|
|
assert.strictEqual(body, '{"a":1}')
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({}, onFinish)
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.onerror(function(err, inctx) {
|
|
assert.strictEqual(err, assertError)
|
|
assert.strictEqual(inctx, ctx)
|
|
inctx.status = assertStatus
|
|
inctx.body = assertBody
|
|
})
|
|
|
|
flaska.requestEnd(assertError, ctx)
|
|
})
|
|
|
|
t.test('calls backup onerror correctly if error throws', function(cb) {
|
|
const assertErrorNotSeen = new Error('should not be seen')
|
|
const assertError = new Error('test')
|
|
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, 500)
|
|
assert.strictEqual(ctx.body.status, 500)
|
|
assert.strictEqual(ctx.body.message, 'Internal Server Error')
|
|
})
|
|
const ctx = createCtx({}, onFinish)
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.onerror(function() {
|
|
throw assertError
|
|
})
|
|
|
|
flaska.requestEnd(assertErrorNotSeen, ctx)
|
|
})
|
|
|
|
let testMethods = ['GET', 'HEAD']
|
|
|
|
testMethods.forEach(function(method) {
|
|
t.describe(method, function() {
|
|
t.test('call res and end correctly when dealing with objects', function(cb) {
|
|
const assertStatus = 202
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 7
|
|
const assertBody = { a: 1 }
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'application/json; charset=utf-8')
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength)
|
|
|
|
if (method === 'GET') {
|
|
assert.ok(body)
|
|
assert.strictEqual(body, '{"a":1}')
|
|
} else {
|
|
assert.notOk(body)
|
|
}
|
|
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with buffers', function(cb) {
|
|
const assertStatus = 202
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 11
|
|
const assertBody = Buffer.from('hello world')
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'application/octet-stream')
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength)
|
|
|
|
if (method === 'GET') {
|
|
assert.ok(body)
|
|
assert.strictEqual(body, assertBody)
|
|
} else {
|
|
assert.notOk(body)
|
|
}
|
|
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with null and no status override', function(cb) {
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 0
|
|
const assertBody = null
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, 204)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.notOk(ctx.headers['Content-Type'])
|
|
assert.notOk(ctx.headers['Content-Length'])
|
|
|
|
assert.strictEqual(body, undefined)
|
|
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: 200,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with null and status override', function(cb) {
|
|
const assertStatus = 202
|
|
// Calculated manually just in case
|
|
const assertBody = null
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.notOk(ctx.headers['Content-Type'])
|
|
assert.strictEqual(ctx.headers['Content-Length'], 0)
|
|
|
|
assert.strictEqual(body, undefined)
|
|
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with strings', function(cb) {
|
|
const assertStatus = 206
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 4
|
|
const assertBody = 'eða'
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'text/plain; charset=utf-8')
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength)
|
|
|
|
if (method === 'GET') {
|
|
assert.ok(body)
|
|
assert.strictEqual(body, assertBody)
|
|
} else {
|
|
assert.notOk(body)
|
|
}
|
|
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with numbers', function(cb) {
|
|
const assertStatus = 211
|
|
// Calculated manually just in case
|
|
const assertBodyLength = 7
|
|
const assertBody = 4214124
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'text/plain; charset=utf-8')
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength)
|
|
|
|
if (method === 'GET') {
|
|
assert.ok(body)
|
|
assert.strictEqual(body, assertBody.toString())
|
|
} else {
|
|
assert.notOk(body)
|
|
}
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
ctx.body = assertBody
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
if (method === 'GET') {
|
|
t.test('call handleRequest if body contains it', function(cb) {
|
|
const assertContentType = 'test/test'
|
|
const assertContentLength = 1241241
|
|
const assertHandle = stub().returnWith(function(checkCtx, secondary) {
|
|
assert.notOk(secondary)
|
|
assert.strictEqual(checkCtx, ctx)
|
|
assert.notOk(ctx.res.writeHead.called)
|
|
ctx.type = assertContentType
|
|
ctx.headers['Content-Length'] = assertContentLength
|
|
return assertBody
|
|
})
|
|
|
|
let body = new FileResponse()
|
|
let assertBody = { pipe: function() {} }
|
|
let onFinish = cb.finish(function(source, target, callback) {
|
|
assert.ok(assertHandle.called)
|
|
assert.ok(ctx.res.writeHead)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
assert.strictEqual(source, assertBody)
|
|
assert.strictEqual(target, ctx.res)
|
|
assert.strictEqual(typeof(callback), 'function')
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
assert.strictEqual(ctx.headers['Content-Type'], assertContentType)
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertContentLength)
|
|
})
|
|
const ctx = createCtx({
|
|
})
|
|
ctx.body = body
|
|
fakeStream.pipeline = onFinish
|
|
body.handleRequest = assertHandle
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
|
|
try {
|
|
flaska.requestEnd(null, ctx)
|
|
} catch (err) {
|
|
cb(err)
|
|
}
|
|
})
|
|
|
|
t.test('call pipeline correctly when dealing with pipe', function(cb) {
|
|
const assertStatus = 211
|
|
const assertType = 'herp/derp'
|
|
const assertBody = { pipe: function() {} }
|
|
|
|
let onFinish = cb.finish(function(source, target, callback) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.headers['Content-Type'], assertType)
|
|
assert.strictEqual(source, assertBody)
|
|
assert.strictEqual(target, ctx.res)
|
|
assert.strictEqual(typeof(callback), 'function')
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
status: assertStatus,
|
|
})
|
|
fakeStream.pipeline = onFinish
|
|
|
|
ctx.body = assertBody
|
|
ctx.type = assertType
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
} else {
|
|
t.test('call handleRequest if body contains it', function(cb) {
|
|
const assertContentType = 'test/test'
|
|
const assertContentLength = 1241241
|
|
const assertHandle = stub().returnWith(function(checkCtx, secondary) {
|
|
assert.notOk(secondary)
|
|
assert.strictEqual(checkCtx, ctx)
|
|
assert.notOk(ctx.res.writeHead.called)
|
|
ctx.type = assertContentType
|
|
ctx.headers['Content-Length'] = assertContentLength
|
|
return null
|
|
})
|
|
|
|
let body = new FileResponse()
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.ok(assertHandle.called)
|
|
assert.ok(ctx.res.writeHead)
|
|
assert.strictEqual(ctx.body, null)
|
|
assert.notOk(body)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
assert.strictEqual(ctx.headers['Content-Type'], assertContentType)
|
|
assert.strictEqual(ctx.headers['Content-Length'], assertContentLength)
|
|
})
|
|
|
|
const ctx = createCtx({
|
|
method: method,
|
|
}, onFinish)
|
|
ctx.body = body
|
|
body.handleRequest = assertHandle
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
|
|
try {
|
|
flaska.requestEnd(null, ctx)
|
|
} catch (err) {
|
|
cb(err)
|
|
}
|
|
})
|
|
|
|
t.test('call pipeline correctly when dealing with pipe', function(cb) {
|
|
const assertStatus = 211
|
|
const assertType = 'herp/derp'
|
|
const assertBody = { pipe: function() {}, destroy: stub() }
|
|
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.headers['Content-Type'], assertType)
|
|
assert.notOk(ctx.headers['Content-Length'])
|
|
assert.notOk(body)
|
|
|
|
assert.ok(assertBody.destroy.called)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
method: method,
|
|
status: assertStatus,
|
|
}, onFinish)
|
|
|
|
ctx.body = assertBody
|
|
ctx.type = assertType
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
t.test('call _onerror with error if handleRequest throws error', function() {
|
|
let body = new FileResponse()
|
|
const assertError = new Error('Secrets of the Goddess')
|
|
let assertBody = { a : 1 }
|
|
const ctx = createCtx({
|
|
status: 204,
|
|
})
|
|
ctx.body = body
|
|
const assertHandle = stub().throws(assertError)
|
|
body.handleRequest = assertHandle
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska._onerror = stub().returnWith(function(err, checkCtx) {
|
|
assert.strictEqual(err, assertError)
|
|
checkCtx.body = assertBody
|
|
})
|
|
flaska.requestEnd(null, ctx)
|
|
assert.ok(assertHandle.called)
|
|
assert.ok(flaska._onerror.called)
|
|
assert.strictEqual(flaska._onerror.firstCall[0], assertError)
|
|
assert.ok(ctx.res.writeHead)
|
|
assert.strictEqual(ctx.body, assertBody)
|
|
})
|
|
|
|
t.test('call res and end correctly when dealing with custom type', function(cb) {
|
|
const assertStatus = 209
|
|
const assertBody = 'test'
|
|
const assertType = 'something/else'
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.headers['Content-Type'], assertType)
|
|
assert.strictEqual(body, assertBody)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({
|
|
status: assertStatus,
|
|
body: assertBody,
|
|
}, onFinish)
|
|
ctx.type = assertType
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
t.test('call pipe should have default type', function(cb) {
|
|
let onFinish = cb.finish(function(source, target) {
|
|
assert.strictEqual(ctx.status, 200)
|
|
assert.strictEqual(ctx.headers['Content-Type'], 'application/octet-stream')
|
|
assert.strictEqual(source, ctx.body)
|
|
assert.strictEqual(target, ctx.res)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({})
|
|
ctx.body = { pipe: function() {} }
|
|
fakeStream.pipeline = onFinish
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
let tests = [
|
|
['png', 'image/png'],
|
|
['jpg', 'image/jpeg'],
|
|
['bmp', 'image/bmp'],
|
|
['js', 'text/javascript'],
|
|
]
|
|
|
|
tests.forEach(function(test) {
|
|
t.test(`call pipe with file extension ${test[0]} should mimetype ${test[1]}`, function(cb) {
|
|
let onFinish = cb.finish(function(source, target) {
|
|
assert.strictEqual(ctx.status, 200)
|
|
assert.strictEqual(ctx.headers['Content-Type'], test[1])
|
|
assert.strictEqual(source, ctx.body)
|
|
assert.strictEqual(target, ctx.res)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
})
|
|
const ctx = createCtx({})
|
|
ctx.body = { pipe: function() {}, path: './bla/test/temp.' + test[0] }
|
|
fakeStream.pipeline = onFinish
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
})
|
|
|
|
t.test('should return immediately if req is finished', function() {
|
|
let onFinish = function() {
|
|
throw new Error('should not be called')
|
|
}
|
|
const ctx = createCtx({ }, onFinish)
|
|
ctx.res.writableEnded = true
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
|
|
const emptyStatuses = [204, 205, 304]
|
|
|
|
emptyStatuses.forEach(function(status) {
|
|
t.test('call res and end correctly when dealing with status ' + status, function(cb) {
|
|
const assertStatus = status
|
|
const assertNotBody = 'test'
|
|
const assertNotType = 'something/else'
|
|
let onFinish = cb.finish(function(body) {
|
|
assert.strictEqual(ctx.status, assertStatus)
|
|
assert.strictEqual(ctx.res.setHeader.callCount, 0)
|
|
assert.ok(ctx.res.writeHead.called)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status)
|
|
assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers)
|
|
assert.notOk(body)
|
|
})
|
|
const ctx = createCtx({
|
|
status: assertStatus,
|
|
body: assertNotBody,
|
|
}, onFinish)
|
|
ctx.type = assertNotType
|
|
|
|
let flaska = new Flaska({}, fakerHttp, fakeStream)
|
|
flaska.requestEnd(null, ctx)
|
|
})
|
|
})
|
|
})
|
|
|
|
t.describe('#requestEnded()', function() {
|
|
t.test('calls destroy if body is pipe and is not closed', function() {
|
|
const ctx = createCtx({
|
|
body: {
|
|
pipe: {},
|
|
closed: false,
|
|
destroy: spy(),
|
|
},
|
|
})
|
|
let flaska = new Flaska({}, fakerHttp)
|
|
flaska._afterCompiled = function() {}
|
|
|
|
flaska.requestEnded(ctx)
|
|
|
|
assert.ok(ctx.body.destroy.called)
|
|
})
|
|
|
|
t.test('not call destroy if body is pipe but is closed', function() {
|
|
const ctx = createCtx({
|
|
body: {
|
|
pipe: {},
|
|
closed: true,
|
|
destroy: spy(),
|
|
}
|
|
})
|
|
let flaska = new Flaska({}, fakerHttp)
|
|
flaska._afterCompiled = function() {}
|
|
|
|
flaska.requestEnded(ctx)
|
|
|
|
assert.notOk(ctx.body.destroy.called)
|
|
})
|
|
|
|
t.test('calls afterCompiled correctly', function() {
|
|
const assertError = new Error('test')
|
|
const assertCtx = createCtx()
|
|
let flaska = new Flaska({}, fakerHttp)
|
|
|
|
flaska._afterCompiled = function(ctx) {
|
|
assert.strictEqual(ctx, assertCtx)
|
|
throw assertError
|
|
}
|
|
|
|
assert.throws(function() {
|
|
flaska.requestEnded(assertCtx)
|
|
}, /test/)
|
|
})
|
|
|
|
t.test('calls afterAsyncCompiled correctly if defined', async function() {
|
|
const assertError = new Error('test')
|
|
const assertCtx = createCtx()
|
|
let flaska = new Flaska({}, fakerHttp)
|
|
flaska.compile()
|
|
|
|
flaska._afterAsyncCompiled = function(ctx) {
|
|
assert.strictEqual(ctx, assertCtx)
|
|
return Promise.resolve().then(function() { return Promise.reject(assertError) })
|
|
}
|
|
|
|
let err = await assert.isRejected(flaska.requestEnded(assertCtx))
|
|
|
|
assert.strictEqual(err, assertError)
|
|
})
|
|
})
|