You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

497 lines
10 KiB

'use strict'
const middie = require('./middie')
const t = require('tap')
const http = require('http')
const serveStatic = require('serve-static')
const test = t.test
test('use no function', t => {
t.plan(3)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
instance.run(req, res)
})
test('use a function', t => {
t.plan(5)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.pass('function called')
next()
}), instance)
instance.run(req, res)
})
test('use two functions', t => {
t.plan(5)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
var counter = 0
instance.use(function (req, res, next) {
t.is(counter++, 0, 'first function called')
next()
}).use(function (req, res, next) {
t.is(counter++, 1, 'second function called')
next()
})
instance.run(req, res)
})
test('stop the middleware chain if one errors', t => {
t.plan(1)
const instance = middie(function (err, a, b) {
t.ok(err, 'error is forwarded')
})
const req = {
url: '/test'
}
const res = {}
instance.use(function (req, res, next) {
next(new Error('kaboom'))
}).use(function (req, res, next) {
t.fail('this should never be called')
next()
})
instance.run(req, res)
})
test('run restricted by path', t => {
t.plan(11)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/test', req.url)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/test', function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/test', function (req, res, next) {
t.equal('/', req.url)
next()
}), instance)
t.equal(instance.use('/no-call', function (req, res, next) {
t.fail('should not call this function')
next()
}), instance)
instance.run(req, res)
})
test('run restricted by path - prefix override', t => {
t.plan(10)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/test/other/one', req.url)
t.equal(b, res)
})
const req = {
url: '/test/other/one'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/test', function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/test', function (req, res, next) {
t.equal('/other/one', req.url)
next()
}), instance)
instance.run(req, res)
})
test('run restricted by path - prefix override 2', t => {
t.plan(10)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/tasks-api/task', req.url)
t.equal(b, res)
})
const req = {
url: '/tasks-api/task'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/tasks-api', function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use('/tasks-api', function (req, res, next) {
t.equal('/task', req.url)
next()
}), instance)
instance.run(req, res)
})
test('run restricted by array path', t => {
t.plan(9)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/test', req.url)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use(['/test', '/other-path'], function (req, res, next) {
t.ok('function called')
next()
}), instance)
t.equal(instance.use(['/no-call', 'other-path'], function (req, res, next) {
t.fail('should not call this function')
next()
}), instance)
instance.run(req, res)
})
test('run array of middleware restricted by path', t => {
t.plan(10)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/test', req.url)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use([function (req, res, next) {
t.ok('function called')
next()
}, function (req, res, next) {
t.ok('function called')
next()
}]), instance)
t.equal(instance.use('/test', [function (req, res, next) {
t.ok('function called')
next()
}, function (req, res, next) {
t.ok('function called')
next()
}]), instance)
instance.run(req, res)
})
test('run array of middleware restricted by array path', t => {
t.plan(10)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal('/test', req.url)
t.equal(b, res)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use([function (req, res, next) {
t.ok('function called')
next()
}, function (req, res, next) {
t.ok('function called')
next()
}]), instance)
t.equal(instance.use(['/test', '/other-path'], [function (req, res, next) {
t.ok('function called')
next()
}, function (req, res, next) {
t.ok('function called')
next()
}]), instance)
instance.run(req, res)
})
test('Should strip the url to only match the pathname', t => {
t.plan(6)
const instance = middie(function (err, a, b) {
t.error(err)
t.equal(a, req)
t.equal(req.url, '/test#foo?bin=baz')
t.equal(b, res)
})
const req = {
url: '/test#foo?bin=baz'
}
const res = {}
t.equal(instance.use('/test', function (req, res, next) {
t.pass('function called')
next()
}), instance)
instance.run(req, res)
})
test('should keep the context', t => {
t.plan(6)
const instance = middie(function (err, a, b, ctx) {
t.error(err)
t.equal(a, req)
t.equal(b, res)
t.ok(ctx.key)
})
const req = {
url: '/test'
}
const res = {}
t.equal(instance.use(function (req, res, next) {
t.pass('function called')
next()
}), instance)
instance.run(req, res, { key: true })
})
test('should add `originalUrl` property to req', t => {
t.plan(2)
const instance = middie(function (err) {
t.error(err)
})
const req = {
url: '/test'
}
const res = {}
instance.use(function (req, res, next) {
t.equal(req.originalUrl, '/test')
next()
})
instance.run(req, res)
})
test('basic serve static', t => {
const instance = middie(function () {
t.fail('the default route should never be called')
})
instance.use(serveStatic(__dirname))
const server = http.createServer(instance.run.bind(instance))
server.listen(0, function () {
http.get(`http://localhost:${server.address().port}/README.md`, function (res) {
t.is(res.statusCode, 200)
res.resume()
server.close()
server.unref()
t.end()
})
})
})
test('limit serve static to a specific folder', t => {
const instance = middie(function () {
t.fail('the default route should never be called')
req.destroy()
server.close()
server.unref()
})
instance.use('/assets', serveStatic(__dirname))
const server = http.createServer(instance.run.bind(instance))
var req
server.listen(0, function () {
req = http.get(`http://localhost:${server.address().port}/assets/README.md`, function (res) {
t.is(res.statusCode, 200)
res.resume()
server.close()
server.unref()
t.end()
})
})
})
test('should match all chain', t => {
t.plan(2)
const instance = middie(function (err, req, res) {
t.error(err)
t.deepEqual(req, {
url: '/inner/in/depth',
originalUrl: '/inner/in/depth',
undefined: true,
null: true,
empty: true,
root: true,
inner: true,
innerSlashed: true,
innerIn: true,
innerInSlashed: true,
innerInDepth: true,
innerInDepthSlashed: true
})
})
const req = {
url: '/inner/in/depth'
}
const res = {}
const prefixes = [
{ prefix: undefined, name: 'undefined' },
{ prefix: null, name: 'null' },
{ prefix: '', name: 'empty' },
{ prefix: '/', name: 'root' },
{ prefix: '/inner', name: 'inner' },
{ prefix: '/inner/', name: 'innerSlashed' },
{ prefix: '/inner/in', name: 'innerIn' },
{ prefix: '/inner/in/', name: 'innerInSlashed' },
{ prefix: '/inner/in/depth', name: 'innerInDepth' },
{ prefix: '/inner/in/depth/', name: 'innerInDepthSlashed' }
]
prefixes.forEach(function (o) {
instance.use(o.prefix, function (req, res, next) {
if (req[o.name]) throw new Error('Called twice!')
req[o.name] = true
next()
})
})
instance.run(req, res)
})
test('should match the same slashed path', t => {
t.plan(3)
const instance = middie(function (err, req, res) {
t.error(err)
t.deepEqual(req, {
url: '/path',
originalUrl: '/path'
})
})
const req = {
url: '/path'
}
const res = {}
instance.use('/path/', function (req, res, next) {
t.pass('function called')
next()
})
instance.use('/path/inner', function (req, res, next) {
t.fail()
next()
})
instance.run(req, res)
})
test('if the function calls res.end the iterator should stop', t => {
t.plan(1)
const instance = middie(function () {
t.fail('we should not be here')
})
const req = {
url: '/test'
}
const res = {
finished: false,
end: function () {
t.pass('res.end')
this.finished = true
}
}
instance
.use(function (req, res, next) {
res.end('hello')
next()
})
.use(function (req, res, next) {
t.fail('we should not be here')
})
instance.run(req, res)
})