Permalink
Browse files

Merge branch 'new-tests'

  • Loading branch information...
2 parents c8ad541 + 31f0b1b commit 219f3318a9737dddc8cc2e7eb6109efbc456c8c7 @tj tj committed Nov 22, 2011
Showing with 855 additions and 2,550 deletions.
  1. +8 −9 Makefile
  2. +1 −1 lib/middleware/basicAuth.js
  3. +107 −29 lib/middleware/bodyParser.js
  4. +1 −1 lib/middleware/csrf.js
  5. +3 −3 lib/middleware/directory.js
  6. +1 −1 lib/middleware/limit.js
  7. +4 −4 lib/middleware/static.js
  8. +2 −14 lib/proto.js
  9. +0 −20 lib/utils.js
  10. +5 −4 package.json
  11. +84 −0 test/basicAuth.js
  12. +0 −106 test/basicAuth.test.js
  13. +257 −0 test/bodyParser.js
  14. +0 −91 test/bodyParser.test.js
  15. +0 −21 test/common.js
  16. +0 −291 test/connect.test.js
  17. +0 −106 test/cookieParser.test.js
  18. +0 −38 test/directory.test.js
  19. +0 −83 test/errorHandler.test.js
  20. +0 −31 test/favicon.test.js
  21. +1 −1 test/fixtures/.hidden
  22. 0 test/fixtures/directory/.hidden
  23. 0 test/fixtures/directory/bar
  24. 0 test/fixtures/directory/baz.js
  25. 0 test/fixtures/directory/foo
  26. +1 −0 test/fixtures/foo bar
  27. +0 −2 test/fixtures/foo.bar.baz.sass
  28. +0 −1 test/fixtures/index.html
  29. 0 test/fixtures/{list → nums}
  30. +0 −3 test/fixtures/script.coffee
  31. +0 −1 test/fixtures/some text.txt
  32. +0 −13 test/fixtures/ssl.crt
  33. +0 −15 test/fixtures/ssl.key
  34. +0 −2 test/fixtures/style.less
  35. +0 −3 test/fixtures/style.sass
  36. +1 −0 test/fixtures/todo.txt
  37. +0 −4 test/fixtures/user.json
  38. +1 −0 test/fixtures/users/index.html
  39. +1 −0 test/fixtures/users/tobi.txt
  40. +0 −208 test/logger.test.js
  41. +0 −38 test/methodOverride.test.js
  42. +31 −0 test/query.js
  43. +0 −30 test/query.test.js
  44. +24 −0 test/responseTime.js
  45. +0 −30 test/responseTime.test.js
  46. +0 −713 test/session.test.js
  47. +174 −0 test/static.js
  48. +0 −312 test/static.test.js
  49. +0 −193 test/staticCache.test.js
  50. +116 −0 test/support/http.js
  51. +32 −66 test/{utils.test.js → utils.js}
  52. +0 −62 test/vhost.test.js
View
17 Makefile
@@ -1,15 +1,14 @@
-TEST = node_modules/.bin/expresso
-TESTS ?= test/*.test.js
SRC = $(shell find lib -type f -name "*.js")
+TESTS = test/*.js
+REPORTER = dot
test:
- @NODE_ENV=test ./$(TEST) \
- -I lib \
- $(TEST_FLAGS) $(TESTS)
-
-test-cov:
- @$(MAKE) test TEST_FLAGS="--cov"
+ @NODE_ENV=test ./node_modules/.bin/mocha \
+ --require should \
+ --reporter $(REPORTER) \
+ --growl \
+ $(TESTS)
docs:
@mkdir -p docs
@@ -25,4 +24,4 @@ site: docclean docs
&& cp -fr /tmp/docs/* . \
&& echo "done"
-.PHONY: site docs test test-cov docclean
+.PHONY: site docs test docclean
View
2 lib/middleware/basicAuth.js
@@ -67,7 +67,7 @@ module.exports = function basicAuth(callback, realm) {
, scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString().split(':');
- if ('Basic' != scheme) return next(400);
+ if ('Basic' != scheme) return next(utils.error(400));
// async
if (callback.length >= 3) {
View
136 lib/middleware/bodyParser.js
@@ -10,7 +10,8 @@
* Module dependencies.
*/
-var qs = require('qs');
+var qs = require('qs')
+ , formidable = require('formidable');
/**
* Extract the mime type from the given request's
@@ -29,10 +30,9 @@ function mime(req) {
/**
* Parse request bodies.
*
- * By default _application/json_ and _application/x-www-form-urlencoded_
- * are supported, however you may map `connect.bodyParser.parse[contentType]`
- * to a function of your choice to replace existing parsers, or implement
- * one for other content-types.
+ * By default _application/json_, _application/x-www-form-urlencoded_,
+ * and _multipart/form-data_ are supported, however you may map `connect.bodyParser.parse[contentType]`
+ * to a function receiving `(req, options, callback)`.
*
* Examples:
*
@@ -43,52 +43,130 @@ function mime(req) {
* }
* );
*
- * Since both _json_ and _x-www-form-urlencoded_ are supported by
- * default, either of the following requests would result in the response
- * of "viewing user tj".
- *
* $ curl -d 'user[name]=tj' http://localhost/
* $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://localhost/
*
+ * Multipart configuration:
+ *
+ * The `options` passed are provided to each parser function.
+ * The _multipart/form-data_ parser merges these with formidable's
+ * IncomingForm object, allowing you to tweak the upload directory,
+ * size limits, etc. For example you may wish to retain the file extension
+ * and change the upload directory:
+ *
+ * server.use(bodyParser({
+ * keepExtensions: true
+ * , uploadDir: '/www/mysite.com/uploads'
+ * }));
+ *
+ * View https://github.com/felixge/node-formidable for more information.
+ *
+ * @param {Object} options
* @return {Function}
* @api public
*/
-exports = module.exports = function bodyParser(){
+exports = module.exports = function bodyParser(options){
+ options = options || {};
return function bodyParser(req, res, next) {
if (req.body) return next();
req.body = {};
if ('GET' == req.method || 'HEAD' == req.method) return next();
var parser = exports.parse[mime(req)];
if (parser) {
- var data = '';
- req.setEncoding('utf8');
- req.on('data', function(chunk) { data += chunk; });
- req.on('end', function(){
- try {
- req.body = data
- ? parser(data)
- : {};
- } catch (err) {
- return next(err);
- }
- next();
- });
+ parser(req, options, next);
} else {
next();
}
}
};
/**
- * Supported decoders.
+ * Parsers.
+ */
+
+exports.parse = {};
+
+/**
+ * Parse application/x-www-form-urlencoded.
+ */
+
+exports.parse['application/x-www-form-urlencoded'] = function(req, options, fn){
+ var buf = '';
+ req.setEncoding('utf8');
+ req.on('data', function(chunk){ buf += chunk });
+ req.on('end', function(){
+ try {
+ req.body = qs.parse(buf);
+ fn();
+ } catch (err){
+ fn(err);
+ }
+ });
+};
+
+/**
+ * Parse application/json.
+ */
+
+exports.parse['application/json'] = function(req, options, fn){
+ var buf = '';
+ req.setEncoding('utf8');
+ req.on('data', function(chunk){ buf += chunk });
+ req.on('end', function(){
+ try {
+ req.body = JSON.parse(buf);
+ fn();
+ } catch (err){
+ fn(err);
+ }
+ });
+};
+
+/**
+ * Parse multipart/form-data.
*
- * - application/x-www-form-urlencoded
- * - application/json
+ * TODO: make multiple support optional
+ * TODO: revisit "error" flag if it's a formidable bug
*/
-exports.parse = {
- 'application/x-www-form-urlencoded': qs.parse
- , 'application/json': JSON.parse
+exports.parse['multipart/form-data'] = function(req, options, fn){
+ var form = new formidable.IncomingForm
+ , data = {}
+ , done;
+
+ Object.keys(options).forEach(function(key){
+ form[key] = options[key];
+ });
+
+ function ondata(name, val){
+ if (Array.isArray(data[name])) {
+ data[name].push(val);
+ } else if (data[name]) {
+ data[name] = [data[name], val];
+ } else {
+ data[name] = val;
+ }
+ }
+
+ form.on('field', ondata);
+ form.on('file', ondata);
+
+ form.on('error', function(err){
+ fn(err);
+ done = true;
+ });
+
+ form.on('end', function(){
+ if (done) return;
+ try {
+ req.body = qs.parse(data);
+ fn();
+ } catch (err) {
+ fn(err);
+ }
+ });
+
+ form.parse(req);
};
View
2 lib/middleware/csrf.js
@@ -83,7 +83,7 @@ module.exports = function csrf(options) {
var val = value(req);
// check
- if (val != token) return next(403);
+ if (val != token) return next(utils.error(403));
next();
}
View
6 lib/middleware/directory.js
@@ -63,10 +63,10 @@ exports = module.exports = function directory(root, options){
, showUp = path != root && path != root + '/';
// null byte(s), bad request
- if (~path.indexOf('\0')) return next(400);
+ if (~path.indexOf('\0')) return next(utils.error(400));
// malicious path, forbidden
- if (0 != path.indexOf(root)) return next(403);
+ if (0 != path.indexOf(root)) return next(utils.error(403));
// check if we have a directory
fs.stat(path, function(err, stat){
@@ -92,7 +92,7 @@ exports = module.exports = function directory(root, options){
}
// not acceptable
- next(406);
+ next(utils.error(406));
});
});
};
View
2 lib/middleware/limit.js
@@ -41,7 +41,7 @@ module.exports = function limit(bytes){
req._limit = true;
// limit by content-length
- if (len && len > bytes) return next(413);
+ if (len && len > bytes) return next(utils.error(413));
// limit
req.on('data', function(chunk){
View
8 lib/middleware/static.js
@@ -104,10 +104,10 @@ var send = exports.send = function(req, res, next, options){
, type;
// null byte(s)
- if (~path.indexOf('\0')) return next(400);
+ if (~path.indexOf('\0')) return next(utils.error(400));
// when root is not given, consider .. malicious
- if (!root && ~path.indexOf('..')) return next(403);
+ if (!root && ~path.indexOf('..')) return next(utils.error(403));
// index.html support
if ('/' == path[path.length - 1]) path += 'index.html';
@@ -116,7 +116,7 @@ var send = exports.send = function(req, res, next, options){
path = normalize(join(root, path));
// malicious path
- if (root && 0 != path.indexOf(root)) return next(403);
+ if (root && 0 != path.indexOf(root)) return next(utils.error(403));
// "hidden" file
if (!hidden && '.' == basename(path)[0]) return next();
@@ -180,7 +180,7 @@ var send = exports.send = function(req, res, next, options){
+ stat.size);
// invalid range
} else {
- return next(416);
+ return next(utils.error(416));
}
}
View
16 lib/proto.js
@@ -12,8 +12,7 @@
var http = require('http')
, parse = require('url').parse
- , utils = require('./utils')
- , assert = require('assert');
+ , utils = require('./utils');
// prototype
@@ -117,12 +116,6 @@ app.handle = function(req, res, out) {
req.originalUrl = req.originalUrl || req.url;
removed = '';
- // next(status) support
- if ('number' == typeof err) {
- status = err;
- err = utils.error(err);
- }
-
// next callback
layer = stack[index++];
@@ -191,12 +184,7 @@ app.handle = function(req, res, out) {
next();
}
} catch (e) {
- if (e instanceof assert.AssertionError) {
- console.error(e.stack + '\n');
- next(e);
- } else {
- next(e);
- }
+ next(e);
}
}
next();
View
20 lib/utils.js
@@ -51,26 +51,6 @@ exports.flatten = function(arr, ret){
};
/**
- * Return md5 hash of the given string and optional encoding,
- * defaulting to hex.
- *
- * utils.md5('wahoo');
- * // => "e493298061761236c96b02ea6aa8a2ad"
- *
- * @param {String} str
- * @param {String} encoding
- * @return {String}
- * @api public
- */
-
-exports.md5 = function(str, encoding){
- return crypto
- .createHash('md5')
- .update(str)
- .digest(encoding || 'hex');
-};
-
-/**
* Merge object b with object a.
*
* var a = { foo: 'bar' }
View
9 package.json
@@ -7,13 +7,14 @@
"author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
"repository": "git://github.com/senchalabs/connect",
"dependencies": {
- "qs": ">= 0.3.2",
- "mime": ">= 0.0.1"
+ "qs": ">= 0.4.0",
+ "mime": ">= 0.0.1",
+ "formidable": "1.0.x"
},
"devDependencies": {
- "expresso": "0.7.6",
"koala": "0.1.2",
- "should": "0.2.1"
+ "should": "0.3.2",
+ "mocha": "*"
},
"main": "index",
"engines": { "node": ">= 0.5.0 < 0.7.0" }
View
84 test/basicAuth.js
@@ -0,0 +1,84 @@
+
+var connect = require('../')
+ , request = require('./support/http');
+
+function test(app, signature) {
+ describe(signature, function(){
+ describe('when missing Authorization', function(){
+ it('should respond with 401 and WWW-Authenticate', function(done){
+ app.request()
+ .get('/')
+ .end(function(res){
+ res.statusCode.should.equal(401);
+ res.headers['www-authenticate'].should.equal('Basic realm="Authorization Required"');
+ done();
+ });
+ })
+ })
+
+ describe('when valid', function(){
+ it('should next()', function(done){
+ app.request()
+ .get('/')
+ .set('Authorization', 'Basic dGo6dG9iaQ==')
+ .end(function(res){
+ res.statusCode.should.equal(200);
+ res.body.should.equal('secret!');
+ done();
+ });
+ })
+ })
+
+ describe('when invalid', function(){
+ it('should respond with 401', function(done){
+ app.request()
+ .get('/')
+ .set('Authorization', 'Basic dGo69iaQ==')
+ .end(function(res){
+ res.statusCode.should.equal(401);
+ res.headers['www-authenticate'].should.equal('Basic realm="Authorization Required"');
+ res.body.should.equal('Unauthorized');
+ done();
+ });
+ })
+ })
+ })
+}
+
+var app = connect();
+
+app.use(connect.basicAuth('tj', 'tobi'));
+
+app.use(function(req, res, next){
+ res.end('secret!');
+});
+
+test(app, 'connect.basicAuth(user, pass)');
+
+
+
+var app = connect();
+
+app.use(connect.basicAuth(function(user, pass){
+ return 'tj' == user && 'tobi' == pass;
+}));
+
+app.use(function(req, res, next){
+ res.end('secret!');
+});
+
+test(app, 'connect.basicAuth(callback)');
+
+
+
+var app = connect();
+
+app.use(connect.basicAuth(function(user, pass, fn){
+ fn(null, 'tj' == user && 'tobi' == pass);
+}));
+
+app.use(function(req, res, next){
+ res.end('secret!');
+});
+
+test(app, 'connect.basicAuth(callback) async');
View
106 test/basicAuth.test.js
@@ -1,106 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , http = require('http')
- , create = require('./common').create;
-
-// sync
-
-var app = create(
- connect.basicAuth(function(user, pass){
- return 'tj' == user && 'tobi' == pass;
- }),
- function(req, res){
- res.end('wahoo');
- }
-);
-
-// async
-
-var User = {
- authenticate: function(query, fn){
- if (query.name == 'tj' && query.pass == 'tobi') {
- fn(null, { name: 'tj' });
- } else {
- fn(new Error('user not found'));
- }
- }
-}
-
-var async = create(
- connect.basicAuth(function(user, pass, fn){
- User.authenticate({ name: user, pass: pass }, fn);
- }),
- function(req, res){
- res.end('wahoo');
- }
-);
-
-module.exports = {
- 'test user / pass options': function(){
- var app = create(
- connect.basicAuth('tj', 'tobi'),
- function(req, res){
- res.send('wahoo');
- }
- );
-
- assert.response(app,
- { url: '/' },
- { body: 'Unauthorized' });
-
- assert.response(app,
- { url: '/', headers: { Authorization: 'Basic dGo6dG9iaQo=' }},
- { body: 'Unauthorized' });
- },
-
- 'test missing Authorization field': function(){
- assert.response(app,
- { url: '/' },
- { body: 'Unauthorized'
- , status: 401
- , headers: {
- 'WWW-Authenticate': 'Basic realm="Authorization Required"'
- }});
- },
-
- 'test authorized': function(){
- assert.response(app,
- { url: '/', headers: { Authorization: 'Basic dGo6dG9iaQ==' }},
- { body: 'wahoo', status: 200 });
- },
-
- 'test unauthorized': function(){
- assert.response(app,
- { url: '/', headers: { Authorization: 'Basic dasdfasdfas' }},
- { body: 'Unauthorized', status: 401 });
- },
-
- 'test bad request': function(){
- assert.response(app,
- { url: '/', headers: { Authorization: 'Foo asdfasdf' }},
- { body: /Bad Request/, status: 400 });
- },
-
- 'test async authorized': function(){
- assert.response(async,
- { url: '/', headers: { Authorization: 'Basic dGo6dG9iaQ==' }},
- { body: 'wahoo', status: 200 });
- },
-
- 'test async unauthorized': function(){
- assert.response(async,
- { url: '/', headers: { Authorization: 'Basic dasdfasdfas' }},
- { body: 'Unauthorized', status: 401 });
- },
-
- 'test async bad request': function(){
- assert.response(async,
- { url: '/', headers: { Authorization: 'Foo asdfasdf' }},
- { body: /Bad Request/, status: 400 });
- },
-};
View
257 test/bodyParser.js
@@ -0,0 +1,257 @@
+
+var connect = require('../');
+
+var app = connect();
+
+app.use(connect.bodyParser());
+
+app.use(function(req, res){
+ res.end(JSON.stringify(req.body));
+});
+
+describe('connect.bodyParser()', function(){
+ it('should default to {}', function(done){
+ app.request()
+ .post('/')
+ .end(function(res){
+ res.body.should.equal('{}');
+ done();
+ })
+ })
+
+ it('should parse JSON', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'application/json')
+ .write('{"user":"tobi"}')
+ .end(function(res){
+ res.body.should.equal('{"user":"tobi"}');
+ done();
+ });
+ })
+
+ it('should parse x-www-form-urlencoded', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'application/x-www-form-urlencoded')
+ .write('user=tobi')
+ .end(function(res){
+ res.body.should.equal('{"user":"tobi"}');
+ done();
+ });
+ })
+
+ describe('with multipart/form-data', function(){
+ it('should populate req.body', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="user"\r\n')
+ .write('\r\n')
+ .write('Tobi')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.body.should.equal('{"user":"Tobi"}');
+ done();
+ });
+ })
+
+ it('should support files', function(done){
+ var app = connect();
+
+ app.use(connect.bodyParser());
+
+ app.use(function(req, res){
+ req.body.user.should.eql({ name: 'Tobi' });
+ req.body.text.path.should.not.include.string('.txt');
+ req.body.text.constructor.name.should.equal('File');
+ res.end(req.body.text.name);
+ });
+
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="user[name]"\r\n')
+ .write('\r\n')
+ .write('Tobi')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
+ .write('\r\n')
+ .write('some text here')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.body.should.equal('foo.txt');
+ done();
+ });
+ })
+
+ it('should expose options to formidable', function(done){
+ var app = connect();
+
+ app.use(connect.bodyParser({
+ keepExtensions: true
+ }));
+
+ app.use(function(req, res){
+ req.body.user.should.eql({ name: 'Tobi' });
+ req.body.text.path.should.include.string('.txt');
+ req.body.text.constructor.name.should.equal('File');
+ res.end(req.body.text.name);
+ });
+
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="user[name]"\r\n')
+ .write('\r\n')
+ .write('Tobi')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
+ .write('\r\n')
+ .write('some text here')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.body.should.equal('foo.txt');
+ done();
+ });
+ })
+
+ it('should work with multiple fields', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="user"\r\n')
+ .write('\r\n')
+ .write('Tobi')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="age"\r\n')
+ .write('\r\n')
+ .write('1')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.body.should.equal('{"user":"Tobi","age":"1"}');
+ done();
+ });
+ })
+
+ it('should support nesting', function(done){
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="user[name]"\r\n')
+ .write('\r\n')
+ .write('tobi')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="user[age]"\r\n')
+ .write('\r\n')
+ .write('1')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="species"\r\n')
+ .write('\r\n')
+ .write('ferret')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.body.should.equal('{"user":{"name":"tobi","age":"1"},"species":"ferret"}');
+ done();
+ });
+ })
+
+ it('should support multiple files of the same name', function(done){
+ var app = connect();
+
+ app.use(connect.bodyParser());
+
+ app.use(function(req, res){
+ req.body.text.should.have.length(2);
+ req.body.text[0].constructor.name.should.equal('File');
+ req.body.text[1].constructor.name.should.equal('File');
+ res.end();
+ });
+
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="text"; filename="foo.txt"\r\n')
+ .write('\r\n')
+ .write('some text here')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
+ .write('\r\n')
+ .write('some more text stuff')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.statusCode.should.equal(200);
+ done();
+ });
+ })
+
+ it('should support nested files', function(done){
+ var app = connect();
+
+ app.use(connect.bodyParser());
+
+ app.use(function(req, res){
+ Object.keys(req.body.docs).should.have.length(2);
+ req.body.docs.foo.name.should.equal('foo.txt');
+ req.body.docs.bar.name.should.equal('bar.txt');
+ res.end();
+ });
+
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-Disposition: form-data; name="docs[foo]"; filename="foo.txt"\r\n')
+ .write('\r\n')
+ .write('some text here')
+ .write('\r\n--foo\r\n')
+ .write('Content-Disposition: form-data; name="docs[bar]"; filename="bar.txt"\r\n')
+ .write('\r\n')
+ .write('some more text stuff')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.statusCode.should.equal(200);
+ done();
+ });
+ })
+
+ it('should next(err) on multipart failure', function(done){
+ var app = connect();
+
+ app.use(connect.bodyParser());
+
+ app.use(function(req, res){
+ res.end('whoop');
+ });
+
+ app.use(function(err, req, res, next){
+ err.message.should.equal('parser error, 16 of 28 bytes parsed');
+ res.statusCode = 500;
+ res.end();
+ });
+
+ app.request()
+ .post('/')
+ .set('Content-Type', 'multipart/form-data; boundary=foo')
+ .write('--foo\r\n')
+ .write('Content-filename="foo.txt"\r\n')
+ .write('\r\n')
+ .write('some text here')
+ .write('Content-Disposition: form-data; name="text"; filename="bar.txt"\r\n')
+ .write('\r\n')
+ .write('some more text stuff')
+ .write('\r\n--foo--')
+ .end(function(res){
+ res.statusCode.should.equal(500);
+ done();
+ });
+ })
+
+ })
+})
View
91 test/bodyParser.test.js
@@ -1,91 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , http = require('http')
- , create = require('./common').create;
-
-var app = create(
- connect.bodyParser(),
- function(req, res){
- res.writeHead(200);
- res.end(JSON.stringify(req.body));
-});
-
-module.exports = {
- 'test x-www-form-urlencoded body': function(){
- assert.response(app,
- { url: '/'
- , data: 'foo=bar'
- , method: 'POST'
- , headers: { 'Content-Type': 'application/x-www-form-urlencoded' }},
- { body: '{"foo":"bar"}' });
- },
-
- 'test PUT x-www-form-urlencoded body': function(){
- assert.response(app,
- { url: '/'
- , data: 'foo=bar'
- , method: 'PUT'
- , headers: { 'Content-Type': 'application/x-www-form-urlencoded' }},
- { body: '{"foo":"bar"}' });
- },
-
- 'test json body': function(){
- assert.response(app,
- { url: '/'
- , data: '{"foo":"bar"}'
- , method: 'PUT'
- , headers: { 'Content-Type': 'application/json' }},
- { body: '{"foo":"bar"}' });
- },
-
- 'test POST with no data': function(){
- assert.response(app,
- { url: '/', method: 'POST' },
- { body: '{}' });
- },
-
- 'test GET with content-type': function(){
- assert.response(app,
- { url: '/', headers: { 'Content-Type': 'application/json' }},
- { body: '{}' });
- },
-
- 'test custom parser': function(){
- connect.bodyParser.parse['application/x-awesome'] = function(str){
- var obj = {}
- , parts = str.split('.');
- obj[parts.shift()] = parts.shift();
- return obj;
- };
-
- assert.response(app,
- { url: '/'
- , method: 'POST'
- , data: 'foo.bar'
- , headers: { 'Content-Type': 'application/x-awesome' }},
- { body: '{"foo":"bar"}' });
- },
-
- 'test mount-safety': function(){
- var app = connect()
- .use(connect.bodyParser())
- .use(function(req, res){
- res.end(req.body.name);
- });
-
- var app2 = connect(connect.bodyParser());
- app2.use('/test', app);
-
- assert.response(http.createServer(app2),
- { url: '/test'
- , method: 'POST'
- , data: '{"name":"tj"}'
- , headers: { 'Content-Type': 'application/json' }},
- { body: 'tj' });
- }
-};
View
21 test/common.js
@@ -1,21 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , http = require('http');
-
-/**
- * App creation helper.
- *
- * @return {HTTPServer}
- */
-
-exports.create = function() {
- var app = connect();
- for (var i = 0, len = arguments.length; i < len; ++i) {
- app.use(arguments[i]);
- }
- return http.createServer(app);
-};
View
291 test/connect.test.js
@@ -1,291 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , exec = require('child_process').exec
- , create = require('./common').create
- , should = require('should')
- , assert = require('assert')
- , https = require('https')
- , http = require('http')
- , fs = require('fs');
-
-module.exports = {
- 'test version': function(){
- connect.version.should.match(/^\d+\.\d+\.\d+$/);
- },
-
- 'test connect()': function(){
- var app = create(
- function(req, res){
- res.end('wahoo');
- }
- );
-
- assert.response(app,
- { url: '/' },
- { body: 'wahoo' });
- },
-
- 'test use()': function(){
- var app = connect();
-
- app.use('/blog', function(req, res){
- res.end('blog');
- });
-
- var ret = app.use(
- function(req, res){
- res.end('default');
- }
- );
-
- ret.should.equal(app);
- app = http.createServer(app);
-
- assert.response(app,
- { url: '/' },
- { body: 'default', status: 200 });
-
- assert.response(app,
- { url: '/blog' },
- { body: 'blog', status: 200 });
- },
-
- 'test "header" event': function(){
- var app = connect();
-
- app.use(function(req, res, next){
- res.on('header', function(){
- if (req.headers['x-foo']) {
- res.setHeader('X-Bar', 'baz');
- }
- });
-
- next();
- });
-
- app.use(function(req, res){
- // FIXME: this fails if you do not have any res._headers
- res.setHeader('Content-Length', 5);
- res.end('hello');
- });
-
- app = http.createServer(app);
-
- assert.response(app,
- { url: '/' },
- function(res){
- res.headers.should.not.have.property('x-foo');
- res.headers.should.not.have.property('x-bar');
- });
-
- assert.response(app,
- { url: '/', headers: { 'X-Foo': 'bar' }},
- { body: 'hello', headers: { 'X-Bar': 'baz' }});
- },
-
- 'test path matching': function(){
- var n = 0
- , app = connect();
-
- app.use('/hello/world', function(req, res, next){
- switch (++n) {
- case 1:
- case 2:
- req.url.should.equal('/');
- break;
- case 3:
- req.originalUrl.should.equal('/hello/world/and/more/segments');
- req.url.should.equal('/and/more/segments');
- break;
- case 4:
- req.url.should.equal('/images/foo.png?with=query&string');
- break;
- }
-
- res.end('hello world');
- });
-
- app.use('/hello', function(req, res, next){
- res.end('hello');
- });
-
- var foo = connect();
- foo.use(function(req, res, next){
- res.end(foo.route);
- });
-
- app.use('/foo', foo);
- app = http.createServer(app);
-
- assert.response(app,
- { url: '/foo' },
- { body: '/foo' });
-
- assert.response(app,
- { url: '/hello' },
- { body: 'hello' });
-
- assert.response(app,
- { url: '/hello/' },
- { body: 'hello' });
-
- assert.response(app,
- { url: '/hello/world' },
- { body: 'hello world' });
-
- assert.response(app,
- { url: '/hello/world/' },
- { body: 'hello world' });
-
- assert.response(app,
- { url: '/hello/world/and/more/segments' },
- { body: 'hello world' });
-
- assert.response(app,
- { url: '/hello/world/images/foo.png?with=query&string' },
- { body: 'hello world' });
- },
-
- 'test unmatched path': function(){
- var app = create();
-
- assert.response(app,
- { url: '/' },
- { body: 'Cannot GET /', status: 404 });
-
- assert.response(app,
- { url: '/foo', method: 'POST' },
- { body: 'Cannot POST /foo', status: 404 });
- },
-
- 'test error handling': function(){
- var calls = 0;
- var app = create(
- function(req, res, next){
- // Pass error
- next(new Error('lame'));
- },
- function(err, req, res, next){
- ++calls;
- err.should.be.an.instanceof(Error);
- req.should.be.a('object');
- res.should.be.a('object');
- next.should.be.a('function');
- req.body = err.message;
- next(err);
- },
- function(err, req, res, next){
- ++calls;
- err.should.be.an.instanceof(Error);
- req.should.be.a('object');
- res.should.be.a('object');
- next.should.be.a('function');
- // Recover exceptional state
- next();
- },
- function(req, res, next){
- res.end(req.body);
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/' },
- { body: 'lame', status: 200 },
- function(){
- calls.should.equal(2);
- });
- },
-
- 'test catch error': function(){
- var app = create(
- function(req, res, next){
- doesNotExist();
- }
- );
-
- assert.response(app,
- { url: '/' },
- { status: 500 });
- },
-
- 'test mounting': function(){
- var app = connect();
-
- app.use('/', function(req, res){
- // TODO: should inherit parent's /hello
- // to become /hello/world/view
- app.route.should.equal('/world/view');
- res.end('viewing hello world');
- });
-
- var app1 = connect();
- app1.use('/world/view', app);
- app1.use('/world', function(req, res){
- app1.route.should.equal('/hello');
- res.end('hello world');
- });
-
- var app2 = connect();
- app2.use('/hello', app1);
- app2.use('/hello', function(req, res){
- app2.route.should.equal('/');
- res.end('hello');
- });
-
- var server = http.createServer(app2);
-
- assert.response(server,
- { url: '/hello/world/view' },
- { body: 'viewing hello world' });
-
- assert.response(server,
- { url: '/hello/world' },
- { body: 'hello world' });
-
- assert.response(server,
- { url: '/hello' },
- { body: 'hello' });
- },
-
- 'test mounting http.Server': function(){
- var app = connect()
- , world = http.createServer(function(req, res){
- res.end('world');
- });
-
- app.use('/hello/', world);
- app = http.createServer(app);
-
- assert.response(app,
- { url: '/hello' },
- { body: 'world' });
- },
-
- 'test .charset': function(){
- var app = create(function(req, res){
- res.charset = 'utf8';
- res.setHeader('Content-Type', 'text/html');
- res.end('test');
- });
-
- assert.response(app,
- { url: '/' },
- { body: 'test'
- , headers: { 'Content-Type': 'text/html; charset=utf8' }});
- },
-
- 'test next(status)': function(){
- var app = create(function(req, res, next){
- next(413);
- });
-
- assert.response(app,
- { url: '/' },
- { body: /Request Entity Too Large/, status: 413 });
- }
-};
View
106 test/cookieParser.test.js
@@ -1,106 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , http = require('http')
- , create = require('./common').create;
-
-var app = create(
- connect.cookieParser(),
- function(req, res, next){
- res.end(JSON.stringify(req.cookies));
- }
-);
-
-var app2 = create(
- connect.cookieParser(),
- function(req, res, next){
- res.end(JSON.stringify(req.cookies.cart));
- }
-);
-
-var app3 = create(
- connect.cookieParser('keyboard cat'),
- function(req, res, next){
- res.write(JSON.stringify(req.cookies));
- res.write(JSON.stringify(req.signedCookies));
- res.end();
- }
-);
-
-module.exports = {
- 'test without cookies': function(){
- assert.response(app,
- { url: '/' },
- { body: '{}' });
- },
-
- 'test single cookie': function(){
- assert.response(app,
- { url: '/', headers: { Cookie: ['sid=123'] }},
- { body: '{"sid":"123"}' });
- },
-
- 'test several cookies': function(){
- assert.response(app,
- { url: '/', headers: { Cookie: ['sid=123', 'name=tj'] }},
- { body: '{"sid":"123","name":"tj"}' });
- },
-
- 'test malformed cookie': function() {
- assert.response(app,
- { url: '/', headers: { Cookie: ['sid=%g23'] }},
- { body: '{"sid":"%g23"}' });
- },
-
- 'test json cookie': function() {
- assert.response(app2,
- { url: '/', headers: { Cookie: ['cart=j:{"foo":"bar"}'] }},
- { body: '{"foo":"bar"}' });
- },
-
- 'test malformed json cookie': function() {
- assert.response(app2,
- { url: '/', headers: { Cookie: ['cart=j:foo'] }},
- { body: '"j:foo"' });
- },
-
- 'test signed cookie without secret': function(){
- assert.response(app,
- { url: '/', headers: { Cookie: ['cart=tobi.DDm3AcVxE9oneYnbmpqxoyhyKsk'] }},
- { body: '{"cart":"tobi.DDm3AcVxE9oneYnbmpqxoyhyKsk"}' });
- },
-
- 'test signed cookie': function(){
- assert.response(app3,
- { url: '/', headers: { Cookie: ['cart=tobi.DDm3AcVxE9oneYnbmpqxoyhyKsk'] }},
- { body: '{}{"cart":"tobi"}' });
- },
-
- 'test invalid signature': function(){
- assert.response(app3,
- { url: '/', headers: { Cookie: ['cart=tobi.DDm3AcVxE9oneYnbmpqxoyhyKskkkkk'] }},
- { body: '{"cart":"tobi.DDm3AcVxE9oneYnbmpqxoyhyKskkkkk"}{}' });
- },
-
- 'test invalid value': function(){
- assert.response(app3,
- { url: '/', headers: { Cookie: ['cart=tobiii.DDm3AcVxE9oneYnbmpqxoyhyKsk'] }},
- { body: '{"cart":"tobiii.DDm3AcVxE9oneYnbmpqxoyhyKsk"}{}' });
- },
-
- 'test signed cookie & regular cookie': function(){
- assert.response(app3,
- { url: '/', headers: { Cookie: ['cart=tobi.DDm3AcVxE9oneYnbmpqxoyhyKsk', 'foo=bar', 'bar=baz'] }},
- { body: '{"foo":"bar","bar":"baz"}{"cart":"tobi"}' });
- },
-
- 'test signed cookie & json cookie': function(){
- assert.response(app3,
- { url: '/', headers: { Cookie: ['cart=j:"test".qBsQN8eUVjODgORcXh8Cbcm1CuM'] }},
- { body: '{}{"cart":"test"}' });
- }
-};
View
38 test/directory.test.js
@@ -1,38 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , create = require('./common').create;
-
-var app = create(
- connect.directory(__dirname + '/fixtures/directory')
-);
-
-module.exports = {
- 'test default': function(){
- assert.response(app,
- { url: '/' },
- { body: 'bar\nbaz.js\nfoo\n' });
- },
-
- 'test Accept: text/plain': function(){
- assert.response(app,
- { url: '/', headers: { Accept: 'text/plain' }},
- { body: 'bar\nbaz.js\nfoo\n' });
- },
-
- 'test Accept: application/json': function(){
- assert.response(app,
- { url: '/', headers: { Accept: 'application/json' }},
- { body: '["bar","baz.js","foo"]' });
- },
-
- 'test forbidden': function(){
- assert.response(app,
- { url: '/../../../' },
- { status: 403 });
- }
-};
View
83 test/errorHandler.test.js
@@ -1,83 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , should = require('should')
- , http = require('http')
- , create = require('./common').create;
-
-module.exports = {
- 'test html': function(){
- var app = create(
- function(req, res, next){
- next(new Error('keyboard cat!'));
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/', headers: { Accept: 'text/html, application/json' }},
- { status: 500
- , headers: { 'Content-Type': 'text/html' }});
- },
-
- 'test json': function(){
- var app = create(
- function(req, res, next){
- next(new Error('keyboard cat!'));
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/', headers: { Accept: 'application/json' }},
- { status: 500
- , headers: { 'Content-Type': 'application/json' }});
- },
-
- 'test text': function(){
- var app = create(
- function(req, res, next){
- next(new Error('keyboard cat!'));
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/', headers: { Accept: 'text/plain' }},
- { status: 500
- , headers: { 'Content-Type': 'text/plain' }});
- },
-
- 'test err.status': function(){
- var app = create(
- function(req, res, next){
- var err = new Error('oh no');
- err.status = 501;
- next(err);
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/' },
- { status: 501 });
- },
-
- 'test custom response code': function(){
- var app = create(
- function(req, res, next){
- res.statusCode = 501;
- throw new Error('oh no');
- },
- connect.errorHandler()
- );
-
- assert.response(app,
- { url: '/' },
- { status: 501 });
- }
-}
View
31 test/favicon.test.js
@@ -1,31 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , http = require('http')
- , create = require('./common').create;
-
-module.exports = {
- 'test headers': function(){
- var app = create(connect.favicon());
-
- assert.response(app,
- { url: '/favicon.ico' },
- { status: 200
- , headers: {
- 'Content-Type': 'image/x-icon'
- , 'Cache-Control': 'public, max-age=86400'
- }});
- },
-
- 'test custom favicon': function(){
- var app = connect();
- app.use(connect.favicon(__dirname + '/../lib/public/favicon.ico'));
- assert.response(http.createServer(app),
- { url: '/favicon.ico' },
- { status: 200, headers: { 'Content-Type': 'image/x-icon' }});
- }
-};
View
2 test/fixtures/.hidden
@@ -1 +1 @@
-hidden
+I am hidden
View
0 test/fixtures/directory/.hidden
No changes.
View
0 test/fixtures/directory/bar
No changes.
View
0 test/fixtures/directory/baz.js
No changes.
View
0 test/fixtures/directory/foo
No changes.
View
1 test/fixtures/foo bar
@@ -0,0 +1 @@
+baz
View
2 test/fixtures/foo.bar.baz.sass
@@ -1,2 +0,0 @@
-foo
- :color #000
View
1 test/fixtures/index.html
@@ -1 +0,0 @@
-<p>Wahoo!</p>
View
0 test/fixtures/list → test/fixtures/nums
File renamed without changes.
View
3 test/fixtures/script.coffee
@@ -1,3 +0,0 @@
-$ = jQuery
-$(document).ready ->
- console.log "Say Hello to CoffeeScript"
View
1 test/fixtures/some text.txt
@@ -1 +0,0 @@
-whoop
View
13 test/fixtures/ssl.crt
@@ -1,13 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICATCCAWoCCQCqn8Q1CZmBhDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
-VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMB4XDTExMDMzMDE3NDcxNloXDTEyMDMyOTE3NDcxNlowRTELMAkG
-A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
-IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAz3tY
-yeOP2bO18sA0BL+IRq21YL5VVFxxHmbHgnx2ZglLtul4AHpAwq0aUk+26UqvkCZe
-tvhlzWCbvQECuFF4lVXs7/6QSw0YheFhmjf8V0LK4FDJC1ueu+AvBsT6UBof/7GG
-EvriOXHgDcoRMJJCY7Y5l/EUBpp29Fyy9KVdtJUCAwEAATANBgkqhkiG9w0BAQUF
-AAOBgQCXm+Qr/BdigkObPgriHyDhBx88jyQL27SRUQbInI2nRuo2t9bgx2bEkK8p
-UtVc6KBe9QxpRbZPH7XpHh8jtZyT1YsX3LqNvVOpDDIO9wb4L9SyXrx4LUckDd6S
-8qa0O8QH6nWt1l6K1tihMsjnN1f66WWnUyzQ/o+bVbJFSjgSgg==
------END CERTIFICATE-----
View
15 test/fixtures/ssl.key
@@ -1,15 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDPe1jJ44/Zs7XywDQEv4hGrbVgvlVUXHEeZseCfHZmCUu26XgA
-ekDCrRpST7bpSq+QJl62+GXNYJu9AQK4UXiVVezv/pBLDRiF4WGaN/xXQsrgUMkL
-W5674C8GxPpQGh//sYYS+uI5ceANyhEwkkJjtjmX8RQGmnb0XLL0pV20lQIDAQAB
-AoGBAL+jyZXod7T4deV7PFDqbEAEMJTkGMKsA9u1yS+wMFf83A9dw/aE9Q4bf0Vp
-1aPT1SdLGY7dDoLNaewAY/fFYJ69F//K2dkh3p0e5sWHn8WpL3dxuymfi4wB3ye/
-1UCfdrVH98RqxFljt7f8dEn2bnAgA4gWKcMvl+YULHpDbfXhAkEA5zS+A7SUOrFJ
-P10803+4DSFnxmilQifR0gE5qBLjUqJKyrRpOttCOzMBNFYAZIB2bsvtppHEXMOB
-XZw0jxML7QJBAOW7Tu7WIb4+hfrtA56qTJgoOy8WwqEPtZIMyl0x2ukQf+3oIXK/
-+Jz14kn4UFaGOxWEnKL3HIqU1g3mqvnOxkkCQEtVihxW+H1vSriUvr8DPIs6uT+S
-1VYK93j/4TN8hAlmzAvkYO1Gh/wWEGxnIVWd7fkIBXVixaKcKUjBHvcHc7kCQD5r
-kXvlpM97T44pfjVLUnp5W/NkfMekbBJd9VIzLKbs+8WZsBTswlFroeu1U6be3Ajx
-ulmxSQkCfdLTHRu5KjkCQAbbBJMgc1yZ1e5wGVbPwFQiAssQ72EGF5s7jdWLFzvP
-julPtSt0Bek4LtEqpOBfvVTH9zDhnVhBFSGEl/JEFvM=
------END RSA PRIVATE KEY-----
View
2 test/fixtures/style.less
@@ -1,2 +0,0 @@
-@red: #cc0000;
-body { color: @red }
View
3 test/fixtures/style.sass
@@ -1,3 +0,0 @@
-body
- :font-size 12px
- :color #000
View
1 test/fixtures/todo.txt
@@ -0,0 +1 @@
+- groceries
View
4 test/fixtures/user.json
@@ -1,4 +0,0 @@
-{
- "name": "tj",
- "email": "tj@vision-media.ca"
-}
View
1 test/fixtures/users/index.html
@@ -0,0 +1 @@
+<p>tobi, loki, jane</p>
View
1 test/fixtures/users/tobi.txt
@@ -0,0 +1 @@
+ferret
View
208 test/logger.test.js
@@ -1,208 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , should = require('should')
- , https = require('https')
- , create = require('./common').create
- , fs = require('fs');
-
-module.exports = {
- 'test http :req[header]': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':req[foo]',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/', headers: { Foo: 'Bar' } },
- function(){
- assert.equal(logLine, 'Bar\n');
- });
- },
-
- 'test http :res[header]': function(){
- var logLine = ''
- var app = create(
- connect.logger({
- format: ':res[content-type]',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/', headers: { Foo: 'Bar' } },
- function(){
- assert.equal(logLine, 'text/plain\n');
- });
- },
-
- 'test http :res[header] default': function(){
- var logLine = ''
- var app = create(
- connect.logger({
- format: ':method :url :res[content-length]',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/' },
- function(){
- assert.equal(logLine, 'GET / -\n');
- });
- },
-
- 'test http :http-version': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':http-version',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/' },
- function(){
- assert.equal(logLine, '1.1\n');
- });
- },
-
- 'test http :response-time': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':response-time',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/' },
- function(){
- assert.type(parseInt(logLine, 10), 'number');
- });
- },
-
- 'test http :remote-addr': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':remote-addr',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/'},
- function(){
- assert.equal(logLine, '127.0.0.1\n');
- });
- },
-
- 'test http :date': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':date',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/'},
- function(){
- assert.doesNotThrow(function(){
- new Date(logLine);
- });
- assert.type(Date.parse(logLine.replace('\n', '')), 'number');
- });
- },
-
- 'test http :method': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':method',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { method: 'post', url: '/' },
- function(){
- assert.equal(logLine, 'POST\n');
- });
- },
-
- 'test http :url': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':url',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/foo/bar?baz=equals&the#ossom' },
- function(){
- assert.equal(logLine, '/foo/bar?baz=equals&the#ossom\n');
- });
- },
-
- 'test http :referrer': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':referrer',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/', headers: { referrer: 'http://google.com' } },
- function(){
- assert.equal(logLine, 'http://google.com\n');
- });
- },
-
- 'test http :user-agent': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':user-agent',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/', headers: { 'user-agent': 'FooBarClient 1.1.0' } },
- function(){
- assert.equal(logLine, 'FooBarClient 1.1.0\n');
- });
- },
-
- 'test http :status': function(){
- var logLine = '';
- var app = create(
- connect.logger({
- format: ':status',
- stream: { write: function(line){ logLine = line; } }
- })
- );
-
- assert.response(app,
- { url: '/' },
- function(){
- assert.equal(logLine, '404\n');
- });
- }
-};
View
38 test/methodOverride.test.js
@@ -1,38 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , should = require('should')
- , http = require('http')
- , create = require('./common').create;
-
-var app = create(
- connect.bodyParser(),
- connect.methodOverride(),
- function(req, res){
- res.end(req.method);
- }
-);
-
-module.exports = {
- 'test request body': function(){
- assert.response(app,
- { url: '/'
- , method: 'POST'
- , data: '_method=put'
- , headers: { 'Content-Type': 'application/x-www-form-urlencoded' }},
- { body: 'PUT' });
- },
-
- 'test x-http-method-override': function(){
- assert.response(app,
- { url: '/'
- , method: 'POST'
- , data: '_method=put'
- , headers: { 'X-HTTP-Method-Override': 'DELETE' }},
- { body: 'DELETE' });
- }
-};
View
31 test/query.js
@@ -0,0 +1,31 @@
+
+var connect = require('../')
+ , request = require('./support/http');
+
+var app = connect();
+
+app.use(connect.query());
+
+app.use(function(req, res){
+ res.end(JSON.stringify(req.query));
+});
+
+describe('connect.query()', function(){
+ it('should parse the query-string', function(done){
+ request(app)
+ .get('/?user[name]=tobi')
+ .end(function(res){
+ res.body.should.equal('{"user":{"name":"tobi"}}');
+ done();
+ });
+ })
+
+ it('should default to {}', function(done){
+ request(app)
+ .get('/')
+ .end(function(res){
+ res.body.should.equal('{}');
+ done();
+ });
+ })
+})
View
30 test/query.test.js
@@ -1,30 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , http = require('http')
- , create = require('./common').create;
-
-var app = create(
- connect.query()
- , function(req, res){
- res.end(JSON.stringify(req.query));
- }
-);
-
-module.exports = {
- 'test empty query string object': function(){
- assert.response(app,
- { url: '/' },
- { body: '{}' });
- },
-
- 'test query string': function(){
- assert.response(app,
- { url: '/?foo=bar' },
- { body: '{"foo":"bar"}' });
- }
-};
View
24 test/responseTime.js
@@ -0,0 +1,24 @@
+
+var connect = require('../');
+
+var app = connect();
+
+app.use(connect.responseTime());
+
+app.use(function(req, res){
+ setTimeout(function(){
+ res.end();
+ }, 20);
+});
+
+describe('connect.responseTime()', function(){
+ it('should set X-Response-Time', function(done){
+ app.request()
+ .get('/')
+ .end(function(res){
+ var n = parseInt(res.headers['x-response-time']);
+ n.should.be.above(20);
+ done();
+ });
+ })
+})
View
30 test/responseTime.test.js
@@ -1,30 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , should = require('should')
- , http = require('http')
- , create = require('./common').create;
-
-var app = create(
- connect.responseTime(),
- function(req, res){
- setTimeout(function(){
- res.end('Hello');
- }, 500);
- }
-);
-
-module.exports = {
- 'test X-Response-Time': function(){
- assert.response(app,
- { url: '/' },
- { body: 'Hello'
- , headers: {
- 'X-Response-Time': /^\d+ms$/
- }});
- }
-};
View
713 test/session.test.js
@@ -1,713 +0,0 @@
-
-/**
- * Module dependencies.
- */
-
-var connect = require('../')
- , assert = require('assert')
- , should = require('should')
- , http = require('http')
- , create = require('./common').create;
-
-// constructors
-
-var MemoryStore = connect.session.MemoryStore
- , Cookie = connect.session.Cookie
- , Session = connect.session.Session;
-
-// settings
-
-var portno = 9900;
-
-// main test app
-
-var app = create(
- connect.cookieParser('keyboard cat')
- , connect.session()
- , function(req, res, next){
- res.end('wahoo');
- }
-);
-
-// SID helper
-
-function sid(res) {
- return /^connect\.sid=([^;]+);/.exec(res.headers['set-cookie'][0])[1];
-}
-
-// expires helper
-
-function expires(res) {
- if (!res.headers['set-cookie']) throw new Error('no Set-Cookie response header field');
- return res.headers['set-cookie'][0].match(/expires=([^;]+)/)[1];
-}
-
-// proxy http.get() to buffer body
-
-var get = http.get;
-http.get = function(options, fn){
- if (!options.buffer) return get.apply(this, arguments);
- get(options, function(res){
- res.body = '';
- res.on('data', function(chunk){ res.body += chunk });
- res.on('end', function(){ fn(res); });
- });
-};
-
-module.exports = {
- 'test exports': function(){
- connect.session.Session.should.be.a('function');
- connect.session.Store.should.be.a('function');
- connect.session.MemoryStore.should.be.a('function');
- },
-
- 'test Set-Cookie': function(){
- assert.response(app, { url: '/' }, function(res) {
- var cookie = res.headers['set-cookie']
- , prev = sid(res);
- cookie.should.match(/^connect\.sid=([^;]+); path=\/; expires=/);
- assert.response(app, { url: '/' }, function(res){
- var cookie = res.headers['set-cookie'];
- cookie.should.match(/^connect\.sid=([^;]+); path=\/; expires=/);
- prev.should.not.equal(sid(res));
- });
- });
- },
-
- 'test SID maintenance': function(){
- assert.response(app, { url: '/' }, function(res){
- var cookie = res.headers['set-cookie']
- , prev = sid(res);
- cookie.should.match(/^connect\.sid=([^;]+); path=\/; expires=/);
- var headers = { Cookie: 'connect.sid=' + prev }
- , n = 5;
-
- // ensure subsequent requests maintain the SID
- while (n--) {
- assert.response(app, { url: '/', headers: headers }, function(res){
- var cookie = res.headers['set-cookie'];
- cookie.should.match(/^connect\.sid=([^;]+); path=\/; expires=/);
- prev.should.equal(sid(res));
- });
- }
- });
- },
-
- 'test SID changing': function(){
- var sids = []
- , n = 5;
-
- // ensure different SIDs
- while (n--) {