genji
Version:
Writing reusable, modular and flexible node.js applications made easy.
315 lines (279 loc) • 9.47 kB
JavaScript
var genji = require('../index');
var http = require('http');
var assert = require('assert');
var request = require('supertest');
var querystring = require('querystring');
var Router = genji.Router;
describe('Plugin', function () {
var core;
var server;
beforeEach(function () {
core = new genji.Core();
server = http.createServer();
});
describe('.parser', function () {
it('should parse json request', function (done) {
core.use('parser');
core.use('router', {urlRoot: '^/json'});
var jsonStr = JSON.stringify({key: "value"});
var routes = {
receiveJSON: {
url: '/receive$',
method: 'POST',
handler: function (context) {
var json = context.json;
assert.equal(json.key, 'value');
assert.equal(context.data, jsonStr);
context.sendJSON({ok: true});
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.post('/json/receive')
.send(jsonStr)
.set('Content-Type', 'application/json')
.set('content-length', jsonStr.length)
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function (err, res) {
if (err) {
throw err;
}
assert.equal(true, res.body.ok);
done();
});
});
it('should parse post form request and url query', function (done) {
core.use('parser');
core.use('router', {urlRoot: '^/json'});
var queryStr = querystring.stringify({key: "value"});
var routes = {
receiveForm: {
url: '^/form/receive',
method: 'POST',
handler: function (context) {
var param = context.param;
assert.equal(param.key, 'value');
assert.equal(context.query.name, 'john');
assert.equal(context.data, queryStr);
context.sendJSON({ok: true});
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.post('/form/receive?name=john')
.send(queryStr)
.set('Content-Type', 'application/x-www-form-urlencoded')
.set('content-length', queryStr.length)
.expect(200)
.expect('Content-Type', 'application/json; charset=utf-8')
.end(function (err, res) {
if (err) {
throw err;
}
assert.equal(true, res.body.ok);
done();
});
});
it('should close connection if max post size exceeded', function (done) {
core.use('parser', {maxIncomingSize: 10});
core.use('router', new Router({urlRoot: '^/json'}));
var data = "01234567890";
var routes = {
receiveMaxExceeded: {
url: '^/max/exceeded',
method: 'POST',
handler: function (context) {
throw new Error('Connection should be closed due to exceeded max post size.');
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.post('/max/exceeded')
.send(data)
.set('Content-Type', 'application/x-www-form-urlencoded')
.expect('Connection', 'close')
.expect(413, "", done);
});
});
describe('.router', function () {
it('should reply 404 and emit error event if url not matched', function (done) {
core.use('router');
var routes = {
indexHome: {
url: '^/$',
method: 'GET',
handler: function (context) {
throw new Error('Request should not be routed here.');
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.get('/not/existent/url')
.expect(404, "Content not found: /not/existent/url", done);
});
});
describe('.securecookie', function () {
var cookie = genji.cookie;
// options for `secure-cookie` middleware
var secureCookieOptions = {
cookieName: '_testSecure',
secureKey: 'cipher-key',
serverKey: 'hmac-key',
cookiePath: '/test',
cookieDomain: 'test.com'
};
// input data
var now = new Date();
var userData = {
cookieId: '12345',
cookieExpires: new Date((new Date(now.toString())).getTime() + 3600 * 24 * 3 * 1000),
cookieData: {a: 1}
};
var testCookiePlugin = {
name: 'TestCookie',
attach: function () {
return function (req, res, go) {
if (req.url === '/sign') {
var parsedData = JSON.parse(req.headers.data);
var cookieOptions = {
path: '/test',
domain: 'test.com'
};
var cookie = [parsedData.cookieId, new Date(parsedData.cookieExpires), parsedData.cookieData, cookieOptions];
this.setCookie('key', 'value', {expires: new Date(parsedData.cookieExpires)});
this.writeHead(200, {'_testSecure': cookie});
this.end();
} else if (req.url === '/verify') {
var session = this.session;
assert.equal(session.cookieId, userData.cookieId);
assert.deepEqual(new Date(session.cookieExpires), userData.cookieExpires);
assert.equal(session.cookieData.a, userData.cookieData.a);
this.writeHead(200, {data: JSON.stringify(session)});
this.end();
}
};
}
};
it('should be able to sign and verify cookies', function (done) {
var site = genji.site();
site.use('securecookie', secureCookieOptions);
site.use('cookie');
site.use(testCookiePlugin);
var server = http.createServer();
site.start(server);
request(server)
.get('/sign')
.set('data', JSON.stringify(userData))
.end(function (err, res) {
var cookies = res.headers['set-cookie'];
var normalCookie = cookie.parse(cookies[0]);
assert.equal('value', normalCookie.key);
var site = genji.site();
site.use('securecookie', secureCookieOptions);
site.use(testCookiePlugin);
var server = http.createServer();
site.start(server);
request(server)
.get('/verify')
.set('Cookie', cookies[1])
.end(function (err, res) {
var parsedData = JSON.parse(res.headers.data);
assert.equal(parsedData.cookieId, userData.cookieId);
assert.deepEqual(new Date(parsedData.cookieExpires), userData.cookieExpires);
assert.equal(parsedData.cookieData.a, userData.cookieData.a);
done();
});
});
});
});
describe('.view', function () {
it('should render and reply the content of file', function (done) {
var engine = {
render: function (str, ctx) {
assert.equal('testing data for crypto', str);
var search = new RegExp(ctx.search);
var result = str.replace(search, ctx.replace);
return result;
}
};
core.use('router');
core.use('view', {engine: engine, rootViewPath: __dirname});
var routes = {
viewHashfileWithPath: {
url: '^/hashfile/with/path',
method: 'GET',
view: function () {
this.render('view/hashfile.html', {search: 'crypto', replace: "view"});
}
},
viewHashfile: {
url: '^/hashfile',
method: 'GET',
view: function () {
this.render({search: 'crypto', replace: "view"});
}
},
viewHashfileCustomCallback: {
method: 'GET',
view: function () {
var self = this;
this.render('view/hashfile.html', {search: 'crypto', replace: "view"}, function (err, html) {
if (err) {
throw err;
}
self.sendHTML(html + '!');
});
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.get('/hashfile/with/path')
.expect(200, "testing data for view", function () {
request(server)
.get('/hashfile')
.expect(200, "testing data for view", function () {
request(server)
.get('/view/hashfile/custom/callback')
.expect(200, "testing data for view!", done);
});
});
});
it('should fail to render and return 503', function (done) {
var engine = {
render: function (str, ctx) {
assert.equal('testing data for crypto', str);
var search = new RegExp(ctx.search);
var result = str.replace(search, ctx.replace);
return result;
}
};
core.use('router');
core.use('view', {engine: engine, rootViewPath: __dirname});
var routes = {
viewHashfileWithPath: {
url: '^/unknow/file',
method: 'GET',
view: function () {
this.render('view/unknow_file.html', {search: 'crypto', replace: "view"});
}
}
};
core.map(routes);
server.on('request', core.getListener());
request(server)
.get('/unknow/file')
.expect(503, "Failed to render file", done);
});
});
});