flaska/test/middlewares.test.mjs

344 lines
9.5 KiB
JavaScript

import os from 'os'
import path from 'path'
import { Buffer } from 'buffer'
import { Eltro as t, assert, stub} from 'eltro'
import { QueryHandler, JsonHandler, FormidableHandler, HttpError } from '../flaska.mjs'
import { createCtx } from './helper.mjs'
import { finished } from 'stream'
import { setTimeout } from 'timers/promises'
t.describe('#QueryHandler()', function() {
let queryHandler = QueryHandler()
t.test('should return a handler', function() {
assert.strictEqual(typeof(queryHandler), 'function')
})
t.test('should support separating query from request url', function() {
const assertItem1 = 'safdsfdsag'
const assertItem2 = 'hello%20world'
const ctx = {
req: {
url: `/some/path?item1=${assertItem1}&ITEM2=${assertItem2}`
}
}
queryHandler(ctx)
assert.strictEqual(ctx.query.get('item1'), assertItem1)
assert.strictEqual(ctx.query.get('ITEM2'), 'hello world')
})
})
t.describe('#JsonHandler()', function() {
let jsonHandler = JsonHandler()
let ctx
t.beforeEach(function() {
ctx = createCtx()
})
t.test('should return a handler', function() {
assert.strictEqual(typeof(jsonHandler), 'function')
})
t.test('should support fetching body from request', async function() {
const assertBody = { a: 1, temp: 'test', hello: 'world'}
let parsed = JSON.stringify(assertBody)
let finished = false
let err = null
jsonHandler(ctx).catch(function(error) {
err = error
}).then(function() {
finished = true
})
assert.ok(ctx.req.on.called)
assert.strictEqual(ctx.req.on.firstCall[0], 'data')
assert.strictEqual(ctx.req.on.secondCall[0], 'end')
assert.strictEqual(finished, false)
ctx.req.on.firstCall[1](Buffer.from(parsed.slice(0, parsed.length / 2)))
assert.strictEqual(finished, false)
ctx.req.on.firstCall[1](Buffer.from(parsed.slice(parsed.length / 2)))
assert.strictEqual(finished, false)
ctx.req.on.secondCall[1]()
await setTimeout(10)
assert.strictEqual(finished, true)
assert.strictEqual(err, null)
assert.notStrictEqual(ctx.req.body, assertBody)
assert.deepStrictEqual(ctx.req.body, assertBody)
})
t.test('should throw if buffer grows too large', async function() {
let defaultLimit = 10 * 1024
let segmentSize = 100
let finished = false
let err = null
jsonHandler(ctx).catch(function(error) {
err = error
}).then(function() {
finished = true
})
for (let i = 0; i < defaultLimit; i += segmentSize) {
ctx.req.on.firstCall[1](Buffer.alloc(segmentSize, 'a'))
}
await setTimeout(10)
assert.strictEqual(finished, true)
assert.notStrictEqual(err, null)
assert.ok(err instanceof HttpError)
assert.strictEqual(err.status, 413)
assert.match(err.message, new RegExp(100 * 103))
assert.match(err.message, new RegExp(defaultLimit))
})
t.test('should throw if buffer is not valid json', async function() {
let finished = false
let err = null
jsonHandler(ctx).catch(function(error) {
err = error
}).then(function() {
finished = true
})
ctx.req.on.firstCall[1](Buffer.alloc(10, 'a'))
ctx.req.on.firstCall[1](Buffer.alloc(10, 'a'))
ctx.req.on.secondCall[1]()
await setTimeout(10)
assert.strictEqual(finished, true)
assert.notStrictEqual(err, null)
assert.ok(err instanceof HttpError)
assert.strictEqual(err.status, 400)
assert.match(err.message, /JSON/)
assert.match(err.message, /Unexpected token a in/i)
assert.strictEqual(err.body.status, 400)
assert.match(err.body.message, /Invalid JSON/i)
assert.match(err.body.message, /Unexpected token a in/i)
assert.strictEqual(err.body.request, 'aaaaaaaaaaaaaaaaaaaa')
})
t.test('should not throw if body is empty', async function() {
let finished = false
let err = null
jsonHandler(ctx).catch(function(error) {
err = error
}).then(function() {
finished = true
})
assert.ok(ctx.req.on.called)
assert.strictEqual(ctx.req.on.firstCall[0], 'data')
assert.strictEqual(ctx.req.on.secondCall[0], 'end')
assert.strictEqual(finished, false)
ctx.req.on.secondCall[1]()
await setTimeout(10)
assert.strictEqual(finished, true)
assert.strictEqual(err, null)
assert.deepStrictEqual(ctx.req.body, {})
})
})
t.describe('#FormidableHandler()', function() {
let formidable
let incomingForm
let ctx
t.beforeEach(function() {
ctx = createCtx()
formidable = {
IncomingForm: stub(),
fsRename: stub().resolves(),
}
incomingForm = {
parse: stub().returnWith(function(req, cb) {
cb(null, {}, { file: { name: 'asdf.png' } })
})
}
formidable.IncomingForm.returns(incomingForm)
})
t.test('should call formidable with correct defaults', async function() {
let handler = FormidableHandler(formidable)
await handler(ctx)
assert.strictEqual(incomingForm.uploadDir, os.tmpdir())
assert.strictEqual(incomingForm.maxFileSize, 8 * 1024 * 1024)
assert.strictEqual(incomingForm.maxFieldsSize, 10 * 1024)
assert.strictEqual(incomingForm.maxFields, 50)
assert.strictEqual(incomingForm.parse.firstCall[0], ctx.req)
})
t.test('should apply fields and rename file before returning', async function() {
const assertFilename = 'Lets love.png'
const assertOriginalPath = 'Hitoshi/Fujima/Yuigi.png'
const assertFile = { a: 1, name: assertFilename, path: assertOriginalPath }
const assertFields = { b: 2, c: 3 }
let handler = FormidableHandler(formidable)
incomingForm.parse.returnWith(function(req, cb) {
cb(null, assertFields, { file: assertFile })
})
assert.notOk(ctx.req.body)
assert.notOk(ctx.req.file)
let prefix = new Date().toISOString().replace(/-/g, '').replace('T', '_').replace(/:/g, '').split('.')[0]
await handler(ctx)
assert.strictEqual(ctx.req.body, assertFields)
assert.strictEqual(ctx.req.file, assertFile)
assert.strictEqual(ctx.req.file.path, path.join(os.tmpdir(), ctx.req.file.filename))
assert.match(ctx.req.file.filename, new RegExp(prefix))
assert.match(ctx.req.file.filename, new RegExp(assertFilename))
assert.ok(formidable.fsRename.called)
assert.strictEqual(formidable.fsRename.firstCall[0], assertOriginalPath)
assert.strictEqual(formidable.fsRename.firstCall[1], ctx.req.file.path)
})
t.test('should throw parse error if parse fails', async function() {
const assertError = new Error('Aozora')
let handler = FormidableHandler(formidable)
incomingForm.parse.returnWith(function(req, cb) {
cb(assertError)
})
let err = await assert.isRejected(handler(ctx))
assert.strictEqual(err, assertError)
})
t.test('should throw rename error if rename fails', async function() {
const assertError = new Error('Aozora')
formidable.fsRename.rejects(assertError)
let handler = FormidableHandler(formidable)
let err = await assert.isRejected(handler(ctx))
assert.strictEqual(err, assertError)
})
t.test('should not call rename if no file is present', async function() {
const assertNotError = new Error('Aozora')
const assertFields = { a: 1 }
formidable.fsRename.rejects(assertNotError)
let handler = FormidableHandler(formidable)
incomingForm.parse.returnWith(function(req, cb) {
cb(null, assertFields, null)
})
await handler(ctx)
assert.strictEqual(ctx.req.body, assertFields)
assert.strictEqual(ctx.req.file, null)
incomingForm.parse.returnWith(function(req, cb) {
cb(null, assertFields, { file: null })
})
await handler(ctx)
assert.strictEqual(ctx.req.body, assertFields)
assert.strictEqual(ctx.req.file, null)
})
t.test('should throw filename error if filename fails', async function() {
const assertError = new Error('Dallaglio Piano')
let handler = FormidableHandler(formidable, {
filename: function() {
throw assertError
}
})
let err = await assert.isRejected(handler(ctx))
assert.strictEqual(err, assertError)
})
t.test('should default to original name of filename returns null', async function() {
const assertFilename = 'Herrscher.png'
let handler = FormidableHandler(formidable, {
filename: function() {
return null
}
})
incomingForm.parse.returnWith(function(req, cb) {
cb(null, { }, { file: { name: assertFilename } })
})
await handler(ctx)
assert.strictEqual(ctx.req.file.filename, assertFilename)
})
t.test('should support multiple filename calls in same second', async function() {
const assertFilename = 'Herrscher.png'
let handler = FormidableHandler(formidable)
await handler(ctx)
let file1 = ctx.req.file
await handler(ctx)
let file2 = ctx.req.file
assert.notStrictEqual(file1, file2)
assert.notStrictEqual(file1.filename, file2.filename)
})
t.test('should support parsing fields as json', async function() {
const assertFields = { b: '2', c: '3', e: 'asdf', f: '{"a": 1}' }
let handler = FormidableHandler(formidable, {
parseFields: true,
})
incomingForm.parse.returnWith(function(req, cb) {
cb(null, assertFields, { file: { name: 'test.png' } })
})
await handler(ctx)
assert.strictEqual(ctx.req.body, assertFields)
assert.strictEqual(ctx.req.body.b, 2)
assert.strictEqual(ctx.req.body.c, 3)
assert.strictEqual(ctx.req.body.e, 'asdf')
assert.deepStrictEqual(ctx.req.body.f, {a: 1})
})
})