import { Eltro as t, spy, assert, stub} from 'eltro' import { 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 = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.body, assertBody) assert.strictEqual(ctx.res.statusCode, assertStatus) 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) cb() } catch (err) { cb(err) } } 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 = function(body) { try { assert.strictEqual(ctx.status, 500) assert.strictEqual(ctx.body.status, 500) assert.strictEqual(ctx.body.message, 'Internal Server Error') cb() } catch (err) { cb(err) } } const ctx = createCtx({}, onFinish) let flaska = new Flaska({}, fakerHttp, fakeStream) flaska.onerror(function() { throw assertError }) flaska.requestEnd(assertErrorNotSeen, ctx) }) 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 = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.body, assertBody) assert.strictEqual(ctx.res.statusCode, assertStatus) 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) cb() } catch (err) { cb(err) } } const ctx = createCtx({ 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 = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.body, assertBody) assert.strictEqual(ctx.res.statusCode, assertStatus) assert.strictEqual(ctx.headers['Content-Type'], 'text/plain; charset=utf-8') assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength) assert.ok(body) 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) cb() } catch (err) { cb(err) } } const ctx = createCtx({ 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 = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.body, assertBody) assert.strictEqual(ctx.res.statusCode, assertStatus) assert.strictEqual(ctx.headers['Content-Type'], 'text/plain; charset=utf-8') assert.strictEqual(ctx.headers['Content-Length'], assertBodyLength) assert.ok(body) assert.strictEqual(body, assertBody.toString()) assert.ok(ctx.res.writeHead.called) assert.strictEqual(ctx.res.writeHead.firstCall[0], ctx.status) assert.strictEqual(ctx.res.writeHead.firstCall[1], ctx.headers) cb() } catch (err) { cb(err) } } const ctx = createCtx({ 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 custom type', function(cb) { const assertStatus = 209 const assertBody = 'test' const assertType = 'something/else' let onFinish = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.res.statusCode, 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) cb() } catch (err) { cb(err) } } const ctx = createCtx({ status: assertStatus, body: assertBody, }, onFinish) ctx.type = assertType let flaska = new Flaska({}, fakerHttp, fakeStream) flaska.requestEnd(null, ctx) }) t.test('call pipeline correctly when dealing with pipe', function(cb) { const assertStatus = 211 const assertType = 'herp/derp' const assertBody = { pipe: function() {} } let onFinish = function(source, target, callback) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.res.statusCode, 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) cb() } catch (err) { cb(err) } } const ctx = createCtx({ status: assertStatus, }) fakeStream.pipeline = onFinish ctx.body = assertBody 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 = function(source, target) { try { assert.strictEqual(ctx.res.statusCode, 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) cb() } catch (err) { cb(err) } } 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 = function(source, target) { try { assert.strictEqual(ctx.res.statusCode, 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) cb() } catch (err) { cb(err) } } 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 = function(body) { try { assert.strictEqual(ctx.status, assertStatus) assert.strictEqual(ctx.res.statusCode, 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) cb() } catch (err) { cb(err) } } 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) }) })