Comparing version 0.10.0-rc1 to 0.10.0-rc2
@@ -45,3 +45,3 @@ | ||
let input = { | ||
...app._global, conf: app.conf, req, res, | ||
...app.global, conf: app.conf, req, res, | ||
flash: req.flash, log: app.log, headers: req.headers, | ||
@@ -85,3 +85,3 @@ query: req.query, params: req.params, body: req.body | ||
if(app.shouldParseBody && req.hasBody) | ||
if(app._shouldParseBody && req.hasBody) | ||
req.body = await parseBody(req); | ||
@@ -88,0 +88,0 @@ |
@@ -99,3 +99,3 @@ const util = require('util'); | ||
return { level, type, ...data, pid, msg, time }; | ||
return { level, type, msg, ...data, pid, time }; | ||
} | ||
@@ -108,3 +108,3 @@ | ||
let entry = getEntry(level, ...args); | ||
entry.app = this.name; | ||
entry.app = this._name; | ||
@@ -111,0 +111,0 @@ let conf = this.conf.log; |
@@ -5,2 +5,3 @@ const | ||
http = require('http'), | ||
assert = require('assert'), | ||
https = require('https'), | ||
@@ -31,12 +32,31 @@ compression = require('compression'), | ||
constructor(conf){ | ||
constructor(opts = {}){ | ||
assert(typeof opts == 'object', | ||
new TypeError('Options argument must be an object')); | ||
this._api = opts.api || noop; | ||
this._startup = opts.startup || noop; | ||
this._shutdown = opts.shutdown || noop; | ||
assert(typeof this._api == 'function', | ||
new TypeError('API builder must be a function')); | ||
assert(typeof this._startup == 'function', | ||
new TypeError('Startup handler must be a function')); | ||
assert(typeof this._shutdown == 'function', | ||
new TypeError('Shutdown handler must be a function')); | ||
// TODO sha1 of host+time+name to identify app | ||
let { name, version } = findPkgInfo(); | ||
this._global = {}; | ||
this._startup = this._shutdown = this._api = noop; | ||
this._confort = new Confort(); | ||
this._router = new Router(this); | ||
this._wsRouter = new WSRouter(this); | ||
this._name = name; | ||
this._version = version; | ||
this._shouldParseBody = opts.shouldParseBody || typeof opts.shouldParseBody == 'undefined'; | ||
this._alwaysRebuildAPI = opts.alwaysRebuildAPI || false; | ||
// TODO sha1 of host+time+name to identify app | ||
// Generate HTTP verb shortcut route methods | ||
@@ -51,11 +71,11 @@ this._routeProxy = METHODS.reduce( (o, m) => | ||
this.global = {}; | ||
this.conf = this._confort.object; | ||
this.shouldParseBody = true; | ||
this.cookieSecret = ''; | ||
this.name = name; | ||
this.version = version; | ||
this.running = false; | ||
this.stopped = Promise.resolve(true); | ||
this.setup(conf); | ||
this.setup(opts.conf); | ||
if(!this._alwaysRebuildAPI) | ||
this._api(this._routeProxy); | ||
} | ||
@@ -79,33 +99,4 @@ | ||
this.conf.port = this.conf.port || (this._ssl ? 443 : 80); | ||
if(this.alwaysRebuildAPI) | ||
this._api(this._routeProxy); | ||
} | ||
startup(handler){ | ||
if(typeof handler != 'function') | ||
throw new TypeError('Startup handler must be a function'); | ||
this._startup = handler; | ||
} | ||
shutdown(handler){ | ||
if(typeof handler != 'function') | ||
throw new TypeError('Shutdown handler must be a function'); | ||
this._shutdown = handler; | ||
} | ||
api(builder){ | ||
if(typeof builder != 'function') | ||
throw new TypeError('API Builder must be a function'); | ||
this._api = builder; | ||
if(!this.alwaysRebuildAPI) | ||
this._api(this._routeProxy); | ||
} | ||
global(object){ | ||
this._global = object; | ||
} | ||
// TODO maybe move api build to constructor | ||
async start(){ | ||
@@ -123,7 +114,9 @@ if(this.running) | ||
if(this.alwaysRebuildAPI) | ||
if(this._alwaysRebuildAPI){ | ||
this._router.clear(); | ||
this._api(this._routeProxy); | ||
} | ||
if(!this._startup.noop) | ||
this.log.debug({ type: 'server' }, 'Starting up %s...', this.name); | ||
this.log.debug({ type: 'server' }, 'Starting up %s...', this._name); | ||
@@ -142,3 +135,3 @@ await this._startup(this); | ||
this.log.info({ type: 'server' }, | ||
'%s v%s is ready on port %s', this.name, this.version, this.conf.port); | ||
'%s v%s is ready on port %s', this._name, this._version, this.conf.port); | ||
@@ -194,3 +187,3 @@ started(true); | ||
- 4xx errors won't spit default body anymore | ||
- expose() to global() | ||
- expose() to app.global | ||
- PID 1 omitted from log entries | ||
@@ -205,2 +198,7 @@ - Added res.type() | ||
- removed user error handler (TMP) | ||
- app.api() to new App(api, ...) | ||
- startup and shutdown | ||
- moved cookieSecret to conf | ||
- constructor argument to OPTS spec | ||
- remove programmatic name and version | ||
*/ |
const querystring = require('querystring'); | ||
const contentType = require('content-type'); | ||
@@ -4,0 +3,0 @@ const getRawBody = require('raw-body'); |
@@ -20,12 +20,2 @@ | ||
function error(status, message, ...args){ | ||
if(typeof status !== 'number') | ||
return handleError(status, this.input); | ||
message = format(message, ...args); | ||
this.status(status).end(message); | ||
this.stackAborted = true; | ||
return getHTTPError(status, message); | ||
} | ||
function assert(status, cond, message, ...args){ | ||
@@ -40,3 +30,3 @@ if(!cond) | ||
set(k, v){ | ||
this.setHeader(k.toLowerCase(), v); | ||
this.setHeader(k, v); | ||
return this; | ||
@@ -51,3 +41,3 @@ }, | ||
type(ct){ | ||
this.set('content-type', SHORT_CONTENT_TYPES[ct] || ct); | ||
this.set('Content-Type', SHORT_CONTENT_TYPES[ct] || ct); | ||
return this; | ||
@@ -68,4 +58,18 @@ }, | ||
error | ||
error(status, message, ...args){ | ||
if(typeof status !== 'number') | ||
return handleError(status, this.input); | ||
if(typeof message == 'string') | ||
message = format(message, ...args); | ||
else if(typeof message != 'undefined' && message !== null){ | ||
message = JSON.stringify(message); | ||
this.type('json'); | ||
} | ||
this.status(status).end(message); | ||
this.stackAborted = true; | ||
return getHTTPError(status, message); | ||
} | ||
}; | ||
@@ -72,0 +76,0 @@ |
@@ -14,6 +14,10 @@ const querystring = require('querystring'); | ||
constructor(app){ | ||
this.app = app; | ||
this.clear(); | ||
} | ||
clear(){ | ||
this.routes = {}; | ||
this.static = {}; | ||
this.dynamic = {}; | ||
this.app = app; | ||
} | ||
@@ -27,3 +31,3 @@ | ||
if(route in this.routes) | ||
if(!this.app._alwaysRebuildAPI && route in this.routes) | ||
throw new Error('Route for \'' + route + '\' is already defined'); | ||
@@ -30,0 +34,0 @@ |
{ | ||
"name": "nodecaf", | ||
"version": "0.10.0-rc1", | ||
"version": "0.10.0-rc2", | ||
"description": "Nodecaf is a framework on top of Express for building RESTful services in a quick and convenient manner.", | ||
@@ -5,0 +5,0 @@ "main": "lib/main.js", |
666
test/spec.js
@@ -17,7 +17,75 @@ const assert = require('assert'); | ||
it('Should fail when Options is not an object', () => { | ||
assert.throws( () => new Nodecaf(false), /Options/ ); | ||
}); | ||
it('Should fail when API builder is not a function', () => { | ||
assert.throws( () => new Nodecaf({ api: 3 }), /API/ ); | ||
}); | ||
it('Should execute the API Builder passing the method funcs', done => { | ||
new Nodecaf({ | ||
api(funcs){ | ||
assert.strictEqual(typeof funcs, 'object'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
it('Should allow registering routes', async () => { | ||
let app = new Nodecaf({ | ||
api({ post, del, patch }){ | ||
post('/foo', ({res}) => res.status(500).end() ); | ||
assert.strictEqual(typeof del, 'function'); | ||
assert.strictEqual(typeof patch, 'function'); | ||
} | ||
}); | ||
await app.start(); | ||
let { assert: { status } } = await base.post('foo'); | ||
status.is(500); | ||
await app.stop(); | ||
}); | ||
it('Should preserve flash vars across handlers in a route', async function(){ | ||
this.timeout(4000); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/bar', | ||
({ flash, next }) => { flash.foo = 'bar'; next(); }, | ||
({ flash, res }) => { | ||
res.type('text/plain'); | ||
res.end(flash.foo); | ||
}); | ||
} | ||
}); | ||
await app.start(); | ||
let { assert: { body } } = await base.get('bar'); | ||
body.exactly('bar'); | ||
await app.stop(); | ||
}); | ||
it('Should NOT bulid the API right away if setup so [opts.alwaysRebuildAPI]', () => { | ||
let app = new Nodecaf({ | ||
alwaysRebuildAPI: true, | ||
api({ get }){ | ||
get('/foobar', ({ res }) => res.end()); | ||
} | ||
}); | ||
assert(!app._router.routes['/foobar']); | ||
}); | ||
it('Should store any settings sent', () => { | ||
let app = new Nodecaf({ key: 'value' }); | ||
let app = new Nodecaf({ conf: { key: 'value' } }); | ||
assert.strictEqual(app.conf.key, 'value'); | ||
}); | ||
it('Should fail when startup handler is not a function', () => { | ||
assert.throws( () => new Nodecaf({ startup: 3 }), /function/ ); | ||
}); | ||
it('Should fail when shutdown handler is not a function', () => { | ||
assert.throws( () => new Nodecaf({ shutdown: 3 }), /function/ ); | ||
}); | ||
}); | ||
@@ -43,3 +111,3 @@ | ||
it('Should start the http server on port sent', async () => { | ||
let app = new Nodecaf({ port: 8765 }); | ||
let app = new Nodecaf({ conf: { port: 8765 } }); | ||
await app.start(); | ||
@@ -52,5 +120,4 @@ let { assert } = await get('http://127.0.0.1:8765/'); | ||
it('Should trigger before start event', async () => { | ||
let app = new Nodecaf(); | ||
let done = false; | ||
app.startup(() => done = true); | ||
let app = new Nodecaf({ startup: () => done = true }); | ||
await app.start(); | ||
@@ -61,5 +128,4 @@ assert(done); | ||
it('Should rebuild the api when setup [this.alwaysRebuildAPI]', async () => { | ||
let app = new Nodecaf(); | ||
app.alwaysRebuildAPI = true; | ||
it('Should rebuild the api when setup so [this.alwaysRebuildAPI]', async () => { | ||
let app = new Nodecaf({ alwaysRebuildAPI: true }); | ||
await app.start(); | ||
@@ -80,96 +146,2 @@ let { assert } = await base.get(''); | ||
describe('#startup', () => { | ||
it('Should fail when startup handler is not a function', () => { | ||
let app = new Nodecaf(); | ||
assert.throws( () => app.startup(), /function/ ); | ||
}); | ||
}); | ||
describe('#shutdown', () => { | ||
it('Should fail when shutdown handler is not a function', () => { | ||
let app = new Nodecaf(); | ||
assert.throws( () => app.shutdown(), /function/ ); | ||
}); | ||
}); | ||
describe('#api', () => { | ||
it('Should fail when builder is not a function', () => { | ||
let app = new Nodecaf(); | ||
assert.throws( () => app.api(), /function/ ); | ||
}); | ||
it('Should execute the callback passing the method funcs', done => { | ||
let app = new Nodecaf(); | ||
app.api(function(funcs){ | ||
assert.strictEqual(typeof funcs, 'object'); | ||
done(); | ||
}); | ||
}); | ||
it('Should allow registering routes', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post, del, patch }){ | ||
post('/foo', ({res}) => res.status(500).end() ); | ||
assert.strictEqual(typeof del, 'function'); | ||
assert.strictEqual(typeof patch, 'function'); | ||
}); | ||
await app.start(); | ||
let { assert: { status } } = await base.post('foo'); | ||
status.is(500); | ||
await app.stop(); | ||
}); | ||
it('Should preserve flash vars across handlers in a route', async function(){ | ||
this.timeout(4000); | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/bar', | ||
({ flash, next }) => { flash.foo = 'bar'; next(); }, | ||
({ flash, res }) => { | ||
res.type('text/plain'); | ||
res.end(flash.foo); | ||
}); | ||
}); | ||
await app.start(); | ||
let { assert: { body } } = await base.get('bar'); | ||
body.exactly('bar'); | ||
await app.stop(); | ||
}); | ||
it('Should NOT bulid the API right away if setup [this.alwaysRebuildAPI]', async () => { | ||
let app = new Nodecaf(); | ||
app.alwaysRebuildAPI = true; | ||
app.api(function({ get }){ | ||
get('/foobar', ({ res }) => res.end()); | ||
}); | ||
app.alwaysRebuildAPI = false; | ||
await app.start(); | ||
let { assert } = await base.get('foobar'); | ||
assert.status.is(404); | ||
await app.stop(); | ||
}); | ||
}); | ||
describe('#global', () => { | ||
it('Should store data to be accessible to all handlers', async () => { | ||
let app = new Nodecaf(); | ||
app.global({ foo: 'foobar' }); | ||
app.api(function({ post }){ | ||
post('/bar', ({ foo, res }) => res.text(foo)); | ||
}); | ||
await app.start(); | ||
let { assert: { body } } = await base.post('bar'); | ||
body.exactly('foobar'); | ||
await app.stop(); | ||
}); | ||
}); | ||
describe('#stop', () => { | ||
@@ -186,5 +158,4 @@ | ||
it('Should trigger after stop event', async () => { | ||
let app = new Nodecaf(); | ||
let done = false; | ||
app.shutdown(() => done = true); | ||
let app = new Nodecaf({ shutdown: () => done = true }); | ||
await app.start(); | ||
@@ -229,3 +200,3 @@ await app.stop(); | ||
it('Should apply settings on top of existing one', () => { | ||
let app = new Nodecaf({ key: 'value' }); | ||
let app = new Nodecaf({ conf: { key: 'value' } }); | ||
app.setup({ key: 'value2', key2: 'value' }); | ||
@@ -237,3 +208,3 @@ assert.strictEqual(app.conf.key, 'value2'); | ||
it('Should load form file when path is sent', () => { | ||
let app = new Nodecaf({ key: 'valueOld' }); | ||
let app = new Nodecaf({ conf: { key: 'valueOld' } }); | ||
app.setup('test/res/conf.toml'); | ||
@@ -243,16 +214,2 @@ assert.strictEqual(app.conf.key, 'value'); | ||
it('Should rebuild the api when setup [this.alwaysRebuildAPI]', async () => { | ||
let app = new Nodecaf(); | ||
app.alwaysRebuildAPI = true; | ||
app._api = function({ get }){ | ||
get('/foobar', ({ res }) => res.end()); | ||
}; | ||
app.setup(); | ||
app.alwaysRebuildAPI = false; | ||
await app.start(); | ||
let { assert: { status} } = await base.get('foobar'); | ||
status.is(200); | ||
await app.stop(); | ||
}); | ||
}); | ||
@@ -265,8 +222,9 @@ | ||
it('Should fail when receiving invalid route handlers', () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
assert.throws(() => post('/foobar', undefined), TypeError); | ||
assert.throws(() => post('/foobar'), /empty/); | ||
post('/foobaz', Function.prototype); | ||
assert.throws(() => post('/foobaz', Function.prototype), /already/); | ||
new Nodecaf({ | ||
api({ post }){ | ||
assert.throws(() => post('/foobar', undefined), TypeError); | ||
assert.throws(() => post('/foobar'), /empty/); | ||
post('/foobaz', Function.prototype); | ||
assert.throws(() => post('/foobaz', Function.prototype), /already/); | ||
} | ||
}); | ||
@@ -276,11 +234,12 @@ }); | ||
it('Should pass all the required args to handler', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/foo', function(obj){ | ||
assert(obj.res && obj.req && obj.next && !obj.body | ||
&& obj.params && obj.query && obj.flash | ||
&& obj.conf && obj.log); | ||
assert(this instanceof Nodecaf); | ||
obj.res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/foo', function(obj){ | ||
assert(obj.res && obj.req && obj.next && !obj.body | ||
&& obj.params && obj.query && obj.flash | ||
&& obj.conf && obj.log); | ||
assert(this instanceof Nodecaf); | ||
obj.res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -293,9 +252,10 @@ await app.start(); | ||
it('Should pass all present parameters to handler', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/fo/:o', Function.prototype); | ||
get('/foo/:bar', function({ params, res }){ | ||
res.badRequest(params.bar !== 'test'); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/fo/:o', Function.prototype); | ||
get('/foo/:bar', function({ params, res }){ | ||
res.badRequest(params.bar !== 'test'); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -308,9 +268,10 @@ await app.start(); | ||
it('Should parse URL query string', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/foobar', ({ query, res, next }) => { | ||
assert.strictEqual(query.foo, 'bar'); | ||
res.end(); | ||
next(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/foobar', ({ query, res, next }) => { | ||
assert.strictEqual(query.foo, 'bar'); | ||
res.end(); | ||
next(); | ||
}); | ||
} | ||
}); | ||
@@ -325,3 +286,2 @@ await app.start(); | ||
let app = new Nodecaf(); | ||
app.api(function(){ }); | ||
await app.start(); | ||
@@ -334,7 +294,8 @@ let { status } = await base.post('foobar'); | ||
it('Should parse object as json response [res.json()]', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/foo', function({ res }){ | ||
res.json('{"hey":"ho"}'); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/foo', function({ res }){ | ||
res.json('{"hey":"ho"}'); | ||
}); | ||
} | ||
}); | ||
@@ -354,9 +315,10 @@ await app.start(); | ||
const FormData = require('form-data'); | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/bar', ({ body, res }) => { | ||
assert(body.foobar.size > 10); | ||
res.set('X-Test', body.foobar.name); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/bar', ({ body, res }) => { | ||
assert(body.foobar.size > 10); | ||
res.set('X-Test', body.foobar.name); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -379,8 +341,9 @@ await app.start(); | ||
it('Should parse JSON request body payloads', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body.foo, 'bar'); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body.foo, 'bar'); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -396,8 +359,9 @@ await app.start(); | ||
it('Should parse Raw request body payloads', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body, '{"foo":"bar"}'); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body, '{"foo":"bar"}'); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -415,8 +379,9 @@ await app.start(); | ||
it('Should parse URLEncoded request body payloads', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body.foo, 'bar'); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert.strictEqual(body.foo, 'bar'); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -434,9 +399,11 @@ await app.start(); | ||
it('Should not parse request body when setup so', async () => { | ||
let app = new Nodecaf(); | ||
app.shouldParseBody = false; | ||
app.api(function({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
assert(!body); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
shouldParseBody: false, | ||
api({ post }){ | ||
post('/foobar', ({ body, res }) => { | ||
console.log(body); | ||
assert(!body); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -455,34 +422,17 @@ await app.start(); | ||
describe('CORS', () => { | ||
it('Should send permissive CORS headers when setup so [cors]', async () => { | ||
let app = new Nodecaf({ cors: true }); | ||
app.api(function({ get }){ | ||
get('/foobar', ({ res }) => res.end() ); | ||
}); | ||
await app.start(); | ||
const { assert } = await base.get('foobar', { 'Origin': 'http://outsider.com' }); | ||
assert.status.is(200); | ||
assert.headers.match('access-control-allow-origin', '*'); | ||
const { assert: { headers } } = await base.options('foobar', { 'Origin': 'http://outsider.com' }); | ||
headers.match('access-control-allow-methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); | ||
await app.stop(); | ||
}); | ||
}); | ||
describe('Assertions', () => { | ||
it('Should throw when condition evaluates to true', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/foo', function({ res }){ | ||
assert.throws( () => res.badRequest(true) ); | ||
assert.throws( () => res.unauthorized(true) ); | ||
assert.throws( () => res.forbidden(true) ); | ||
assert.throws( () => res.notFound(true) ); | ||
assert.throws( () => res.conflict(true) ); | ||
assert.throws( () => res.gone(true) ); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/foo', function({ res }){ | ||
assert.throws( () => res.badRequest(true) ); | ||
assert.throws( () => res.unauthorized(true) ); | ||
assert.throws( () => res.forbidden(true) ); | ||
assert.throws( () => res.notFound(true) ); | ||
assert.throws( () => res.conflict(true) ); | ||
assert.throws( () => res.gone(true) ); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -495,13 +445,14 @@ await app.start(); | ||
it('Should do nothing when condition evaluates to false', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ get }){ | ||
get('/foo', function({ res }){ | ||
assert.doesNotThrow( () => res.badRequest(false) ); | ||
assert.doesNotThrow( () => res.unauthorized(false) ); | ||
assert.doesNotThrow( () => res.forbidden(false) ); | ||
assert.doesNotThrow( () => res.notFound(false) ); | ||
assert.doesNotThrow( () => res.conflict(false) ); | ||
assert.doesNotThrow( () => res.gone(false) ); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ get }){ | ||
get('/foo', function({ res }){ | ||
assert.doesNotThrow( () => res.badRequest(false) ); | ||
assert.doesNotThrow( () => res.unauthorized(false) ); | ||
assert.doesNotThrow( () => res.forbidden(false) ); | ||
assert.doesNotThrow( () => res.notFound(false) ); | ||
assert.doesNotThrow( () => res.conflict(false) ); | ||
assert.doesNotThrow( () => res.gone(false) ); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -519,7 +470,8 @@ await app.start(); | ||
it('Should handle Error thrown sync on the route', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/unknown', () => { | ||
throw new Error('othererr'); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/unknown', () => { | ||
throw new Error('othererr'); | ||
}); | ||
} | ||
}); | ||
@@ -533,13 +485,14 @@ await app.start(); | ||
it('Should handle Error injected sync on the route', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/known', ({ res }) => { | ||
throw res.error(404); | ||
}); | ||
post('/unknown', ({ res }) => { | ||
throw res.error(new Error('errfoobar')); | ||
}); | ||
post('/serverfault', ({ res }) => { | ||
throw res.error(501); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/known', ({ res }) => { | ||
throw res.error(404); | ||
}); | ||
post('/unknown', ({ res }) => { | ||
throw res.error(new Error('errfoobar')); | ||
}); | ||
post('/serverfault', ({ res }) => { | ||
throw res.error(501, { test: 'foo' }); | ||
}); | ||
} | ||
}); | ||
@@ -557,7 +510,8 @@ await app.start(); | ||
it('Should handle Rejection on async route', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/async', async () => { | ||
await new Promise((y, n) => n()); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/async', async () => { | ||
await new Promise((y, n) => n()); | ||
}); | ||
} | ||
}); | ||
@@ -571,17 +525,18 @@ await app.start(); | ||
it('Should handle Error injected ASYNC on the route', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/known', ({ res }) => { | ||
fs.readdir('.', function(){ | ||
res.error(404, 'errfoobar'); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/known', ({ res }) => { | ||
fs.readdir('.', function(){ | ||
res.error(404, 'errfoobar'); | ||
}); | ||
}); | ||
}); | ||
post('/unknown', async ({ res }) => { | ||
await fs.readdir('.', function(){ | ||
res.error(new Error('errfoobar')); | ||
post('/unknown', async ({ res }) => { | ||
await fs.readdir('.', function(){ | ||
res.error(new Error('errfoobar')); | ||
}); | ||
}); | ||
}); | ||
post('/unknown/object', () => { | ||
throw 'resterr'; | ||
}); | ||
post('/unknown/object', () => { | ||
throw 'resterr'; | ||
}); | ||
} | ||
}); | ||
@@ -658,9 +613,10 @@ await app.start(); | ||
it('Should log given event', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/foo', ({ log, res }) => { | ||
let entry = log.info('foobar'); | ||
assert.strictEqual(entry.msg, 'foobar'); | ||
res.end(); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/foo', ({ log, res }) => { | ||
let entry = log.info('foobar'); | ||
assert.strictEqual(entry.msg, 'foobar'); | ||
res.end(); | ||
}); | ||
} | ||
}); | ||
@@ -684,32 +640,2 @@ await app.start(); | ||
describe('HTTPS', () => { | ||
const https = require('https'); | ||
it('Should start HTTPS server when specified', async function(){ | ||
let app = new Nodecaf({ | ||
ssl: { | ||
key: './test/res/key.pem', | ||
cert: './test/res/cert.pem' | ||
} | ||
}); | ||
app.api(function({ get }){ | ||
get('/foo', ({ res }) => res.end('bar') ); | ||
}); | ||
await app.start(); | ||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; | ||
let res = await new Promise( resolve => | ||
https.get('https://localhost/foo', resolve) ); | ||
await new Promise( resolve => | ||
res.on('data', chunk => { | ||
assert.strictEqual(chunk.toString(), 'bar'); | ||
resolve(); | ||
}) ); | ||
await app.stop(); | ||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 1; | ||
}); | ||
}); | ||
describe('Regression', () => { | ||
@@ -719,7 +645,8 @@ const WebSocket = require('ws'); | ||
it('Should handle errors even when error event has no listeners', async () => { | ||
let app = new Nodecaf(); | ||
app.api(function({ post }){ | ||
post('/bar', () => { | ||
throw new Error('errfoobar'); | ||
}); | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/bar', () => { | ||
throw new Error('errfoobar'); | ||
}); | ||
} | ||
}); | ||
@@ -788,16 +715,17 @@ await app.start(); | ||
let count = 0; | ||
let app = new Nodecaf(); | ||
app.api(({ ws }) => { | ||
ws('/foo', { | ||
connect: () => count++, | ||
async message({ message }){ | ||
assert.strictEqual('foobar', message); | ||
await app.stop(); | ||
count++; | ||
}, | ||
close(){ | ||
assert.strictEqual(count, 2); | ||
done(); | ||
} | ||
}); | ||
let app = new Nodecaf({ | ||
api({ ws }){ | ||
ws('/foo', { | ||
connect: () => count++, | ||
async message({ message }){ | ||
assert.strictEqual('foobar', message); | ||
await app.stop(); | ||
count++; | ||
}, | ||
close(){ | ||
assert.strictEqual(count, 2); | ||
done(); | ||
} | ||
}); | ||
} | ||
}); | ||
@@ -830,17 +758,18 @@ (async function(){ | ||
let count = 0; | ||
let app = new Nodecaf(); | ||
app.api(({ ws }) => { | ||
ws('/foo', { | ||
connect: () => count++, | ||
error: Function.prototype, | ||
async message({ message }){ | ||
assert.strictEqual('foobar', message); | ||
await app.stop(); | ||
count++; | ||
}, | ||
close(){ | ||
assert.strictEqual(count, 2); | ||
done(); | ||
} | ||
}); | ||
let app = new Nodecaf({ | ||
api({ ws }){ | ||
ws('/foo', { | ||
connect: () => count++, | ||
error: Function.prototype, | ||
async message({ message }){ | ||
assert.strictEqual('foobar', message); | ||
await app.stop(); | ||
count++; | ||
}, | ||
close(){ | ||
assert.strictEqual(count, 2); | ||
done(); | ||
} | ||
}); | ||
} | ||
}); | ||
@@ -858,4 +787,5 @@ (async function(){ | ||
it('Should reject connection to path that is not setup', function(done){ | ||
let app = new Nodecaf(); | ||
app.api(({ ws }) => ws('/foo', {})); | ||
let app = new Nodecaf({ | ||
api: ({ ws }) => ws('/foo', {}) | ||
}); | ||
(async function(){ | ||
@@ -898,8 +828,70 @@ await app.start(); | ||
describe('Other Features', function(){ | ||
const https = require('https'); | ||
it('Should delay server initialization by given milliseconds [delay]', async function(){ | ||
let app = new Nodecaf({ delay: 1500 }); | ||
app.api(function({ get }){ | ||
get('/foobar', ({ res }) => res.end()); | ||
it('Should start HTTPS server when specified', async function(){ | ||
let app = new Nodecaf({ | ||
conf: { | ||
ssl: { | ||
key: './test/res/key.pem', | ||
cert: './test/res/cert.pem' | ||
} | ||
}, | ||
api({ get }){ | ||
get('/foo', ({ res }) => res.end('bar') ); | ||
} | ||
}); | ||
await app.start(); | ||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; | ||
let res = await new Promise( resolve => | ||
https.get('https://localhost/foo', resolve) ); | ||
await new Promise( resolve => | ||
res.on('data', chunk => { | ||
assert.strictEqual(chunk.toString(), 'bar'); | ||
resolve(); | ||
}) ); | ||
await app.stop(); | ||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 1; | ||
}); | ||
it('Should send permissive CORS headers when setup so [cors]', async () => { | ||
let app = new Nodecaf({ | ||
conf: { cors: true }, | ||
api({ get }){ | ||
get('/foobar', ({ res }) => res.end() ); | ||
} | ||
}); | ||
await app.start(); | ||
const { assert } = await base.get('foobar', { 'Origin': 'http://outsider.com' }); | ||
assert.status.is(200); | ||
assert.headers.match('access-control-allow-origin', '*'); | ||
const { assert: { headers } } = await base.options('foobar', { 'Origin': 'http://outsider.com' }); | ||
headers.match('access-control-allow-methods', 'GET,HEAD,PUT,PATCH,POST,DELETE'); | ||
await app.stop(); | ||
}); | ||
it('Should store data to be accessible to all handlers [app.global]', async () => { | ||
let app = new Nodecaf({ | ||
api({ post }){ | ||
post('/bar', ({ foo, res }) => { | ||
res.text(foo); | ||
}) | ||
} | ||
}); | ||
app.global.foo = 'foobar'; | ||
await app.start(); | ||
let { assert: { body } } = await base.post('bar'); | ||
body.exactly('foobar'); | ||
await app.stop(); | ||
}); | ||
it('Should delay server initialization by given milliseconds [conf.delay]', async function(){ | ||
let app = new Nodecaf({ | ||
conf: { delay: 1500 }, | ||
api({ get }){ | ||
get('/foobar', ({ res }) => res.end()); | ||
} | ||
}); | ||
let ps = app.start(); | ||
@@ -906,0 +898,0 @@ await new Promise(done => setTimeout(done, 400)); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
90446
1390