Files
expressjs.com/2x/tests.md
2014-09-17 23:50:47 +05:30

92 KiB

TOC

# app.all() should add a router per method.
var app = express();

app.all('/tobi', function(req, res){
  res.end(req.method);
});

request(app)
.put('/tobi')
.expect('PUT', function(){
  request(app)
  .get('/tobi')
  .expect('GET', done);
});

should .

var app = express()
  , n = 0;

app.all('/*', function(req, res, next){
  if (n++) return done(new Error('DELETE called several times'));
  next();
});

request(app)
.delete('/tobi')
.expect(404, done);
# app.del() should alias app.delete().
var app = express();

app.del('/tobi', function(req, res){
  res.end('deleted tobi!');
});

request(app)
.delete('/tobi')
.expect('deleted tobi!', done);
# app ## .engine(ext, fn) should map a template engine.
var app = express();

app.set('views', __dirname + '/fixtures');
app.engine('.html', render);
app.locals.user = { name: 'tobi' };

app.render('user.html', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should work without leading ".".

var app = express();

app.set('views', __dirname + '/fixtures');
app.engine('html', render);
app.locals.user = { name: 'tobi' };

app.render('user.html', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should work "view engine" setting.

var app = express();

app.set('views', __dirname + '/fixtures');
app.engine('html', render);
app.set('view engine', 'html');
app.locals.user = { name: 'tobi' };

app.render('user', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})
# HEAD should default to GET.
var app = express();

app.get('/tobi', function(req, res){
  // send() detects HEAD
  res.send('tobi');
});

request(app)
.head('/tobi')
.expect(200, done);
# app.head() should override.
var app = express()
  , called;

app.head('/tobi', function(req, res){
  called = true;
  res.end('');
});

app.get('/tobi', function(req, res){
  assert(0, 'should not call GET');
  res.send('tobi');
});

request(app)
.head('/tobi')
.expect(200, function(){
  assert(called);
  done();
});
# app should inherit from event emitter.
var app = express();
app.on('foo', done);
app.emit('foo');
# app.parent should return the parent when mounted.
var app = express()
  , blog = express()
  , blogAdmin = express();

app.use('/blog', blog);
blog.use('/admin', blogAdmin);

assert(!app.parent, 'app.parent');
blog.parent.should.equal(app);
blogAdmin.parent.should.equal(blog);
# app.route should return the mounted path.
var app = express()
  , blog = express()
  , blogAdmin = express();

app.use('/blog', blog);
blog.use('/admin', blogAdmin);

app.route.should.equal('/');
blog.route.should.equal('/blog');
blogAdmin.route.should.equal('/admin');
# app.path() should return the canonical.
var app = express()
  , blog = express()
  , blogAdmin = express();

app.use('/blog', blog);
blog.use('/admin', blogAdmin);

app.path().should.equal('');
blog.path().should.equal('/blog');
blogAdmin.path().should.equal('/blog/admin');
# in development should disable "view cache".
var app = express();
app.enabled('view cache').should.be.false;
# in production should enable "view cache".
process.env.NODE_ENV = 'production';
var app = express();
app.enabled('view cache').should.be.true;
process.env.NODE_ENV = 'test';
# app.listen() should wrap with an HTTP server.
var app = express();

app.del('/tobi', function(req, res){
  res.end('deleted tobi!');
});

var server = app.listen(9999, function(){
  server.close();
  done();
});
# app ## .locals(obj) should merge locals.
var app = express();
Object.keys(app.locals).should.eql(['use', 'settings']);
app.locals({ user: 'tobi', age: 1 });
app.locals({ age: 2 });
Object.keys(app.locals).should.eql(['use', 'settings', 'user', 'age']);
app.locals.user.should.equal('tobi');
app.locals.age.should.equal(2);
## .locals.settings should expose app settings.
var app = express();
app.set('title', 'House of Manny');
var obj = app.locals.settings;
obj.should.have.property('env', 'test');
obj.should.have.property('title', 'House of Manny');
# app ## .locals.use(fn) should run in parallel on res.render().
var app = express();
var calls = [];
app.set('views', __dirname + '/fixtures');

app.locals.first = 'tobi';

app.locals.use(function(req, res, done){
  process.nextTick(function(){
    calls.push('one');
    res.locals.last = 'holowaychuk';
    done();
  });
});

app.locals.use(function(req, res, done){
  process.nextTick(function(){
    calls.push('two');
    res.locals.species = 'ferret';
    done();
  });
});

app.use(function(req, res){
  calls.push('use');
  res.render('pet.jade');
});

request(app)
.get('/')
.end(function(res){
  calls.should.eql(['use', 'one', 'two']);
  res.body.should.equal('<p>tobi holowaychuk is a ferret</p>');
  done();
})

should not override res.render() locals.

var app = express();

app.set('views', __dirname + '/fixtures');
app.locals.first = 'tobi';

app.locals.use(function(req, res){
  res.locals.last = 'holowaychuk';
  res.locals.species = 'ferret';
});

app.use(function(req, res){
  res.render('pet.jade', { last: 'ibot' });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi ibot is a ferret</p>');
  done();
})
### with arity < 3 should done() for you.
var app = express();

app.set('views', __dirname + '/fixtures');
app.locals.first = 'tobi';

app.locals.use(function(req, res){
  res.locals.last = 'holowaychuk';
  res.locals.species = 'ferret';
});

app.use(function(req, res){
  res.render('pet.jade');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi holowaychuk is a ferret</p>');
  done();
})
# OPTIONS should default to the routes defined.
var app = express();

app.del('/', function(){});
app.get('/users', function(req, res){});
app.put('/users', function(req, res){});

request(app)
.options('/users')
.end(function(res){
  res.body.should.equal('GET,PUT');
  res.headers.should.have.property('content-type');
  res.headers.should.have.property('allow', 'GET,PUT');
  done();
});
# app.options() should override the default behavior.
var app = express();

app.options('/users', function(req, res){
  res.set('Allow', 'GET');
  res.send('GET');
});

app.get('/users', function(req, res){});
app.put('/users', function(req, res){});

request(app)
.options('/users')
.end(function(res){
  res.body.should.equal('GET');
  res.headers.should.have.property('allow', 'GET');
  done();
});
# app ## .param(fn) should map app.param(name, ...) logic.
var app = express();

app.param(function(name, regexp){
  if (regexp instanceof RegExp) {
    return function(req, res, next, val){
      var captures;
      if (captures = regexp.exec(String(val))) {
        req.params[name] = captures[1];
        next();
      } else {
        next('route');
      }
    }
  }
})

app.param(':name', /^([a-zA-Z]+)$/);

app.get('/user/:name', function(req, res){
  res.send(req.params.name);
});

request(app)
.get('/user/tj')
.end(function(res){
  res.body.should.equal('tj');
  request(app)
  .get('/user/123')
  .end(function(res){
    res.should.have.status(404);
    done();
  });
});
## .param(names, fn) should map the array.
var app = express();

app.param(['id', 'uid'], function(req, res, next, id){
  id = Number(id);
  if (isNaN(id)) return next('route');
  req.params.id = id;
  next();
});

app.get('/post/:id', function(req, res){
  var id = req.params.id;
  id.should.be.a('number');
  res.send('' + id);
});

app.get('/user/:uid', function(req, res){
  var id = req.params.id;
  id.should.be.a('number');
  res.send('' + id);
});

request(app)
.get('/user/123')
.end(function(res){
  res.body.should.equal('123');

  request(app)
  .get('/post/123')
  .end(function(res){
    res.body.should.equal('123');
    done();
  })
})
## .param(name, fn) should map logic for a single param.
var app = express();

app.param('id', function(req, res, next, id){
  id = Number(id);
  if (isNaN(id)) return next('route');
  req.params.id = id;
  next();
});

app.get('/user/:id', function(req, res){
  var id = req.params.id;
  id.should.be.a('number');
  res.send('' + id);
});

request(app)
.get('/user/123')
.end(function(res){
  res.body.should.equal('123');
  done();
})
# app ## .render(name, fn) should support absolute paths.
var app = express();

app.locals.user = { name: 'tobi' };

app.render(__dirname + '/fixtures/user.jade', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should support absolute paths with "view engine".

var app = express();

app.set('view engine', 'jade');
app.locals.user = { name: 'tobi' };

app.render(__dirname + '/fixtures/user', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should expose app.locals.

var app = express();

app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };

app.render('user.jade', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should support index..

var app = express();

app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');

app.render('blog/post', function(err, str){
  if (err) return done(err);
  str.should.equal('<h1>blog post</h1>');
  done();
})
### when an error occurs should invoke the callback.
var app = express();

app.set('views', __dirname + '/fixtures');

app.render('user.jade', function(err, str){
  // nextTick to prevent cyclic
  process.nextTick(function(){
    err.message.should.match(/user is not defined/);
    done();
  });
})
### when an extension is given should render the template.
var app = express();

app.set('views', __dirname + '/fixtures');

app.render('email.jade', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>This is an email</p>');
  done();
})
### when "view engine" is given should render the template.
var app = express();

app.set('view engine', 'jade');
app.set('views', __dirname + '/fixtures');

app.render('email', function(err, str){
  if (err) return done(err);
  str.should.equal('<p>This is an email</p>');
  done();
})
## .render(name, options, fn) should render the template.
var app = express();

app.set('views', __dirname + '/fixtures');

var user = { name: 'tobi' };

app.render('user.jade', { user: user }, function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should expose app.locals.

var app = express();

app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };

app.render('user.jade', {}, function(err, str){
  if (err) return done(err);
  str.should.equal('<p>tobi</p>');
  done();
})

should give precedence to app.render() locals.

var app = express();

app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };

app.render('user.jade', { user: jane }, function(err, str){
  if (err) return done(err);
  str.should.equal('<p>jane</p>');
  done();
})
# app ## .request should extend the request prototype.
var app = express();

app.request.querystring = function(){
  return require('url').parse(this.url).query;
};

app.use(function(req, res){
  res.end(req.querystring());
});

request(app)
.get('/foo?name=tobi')
.end(function(res){
  res.body.should.equal('name=tobi');
  done();
});
# app ## .response should extend the response prototype.
var app = express();

app.response.shout = function(str){
  this.send(str.toUpperCase());
};

app.use(function(req, res){
  res.shout('hey');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('HEY');
  done();
});

should not be influenced by other app protos.

var app = express()
  , app2 = express();

app.response.shout = function(str){
  this.send(str.toUpperCase());
};

app2.response.shout = function(str){
  this.send(str);
};

app.use(function(req, res){
  res.shout('hey');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('HEY');
  done();
});
# app.router should be .use()able.
var app = express();

var calls = [];

app.use(function(req, res, next){
  calls.push('before');
  next();
});

app.use(app.router);

app.use(function(req, res, next){
  calls.push('after');
  res.end();
});

app.get('/', function(req, res, next){
  calls.push('GET /')
  next();
});

request(app)
.get('/')
.end(function(res){
  calls.should.eql(['before', 'GET /', 'after'])
  done();
})

should be auto .use()d on the first app.VERB() call.

var app = express();

var calls = [];

app.use(function(req, res, next){
  calls.push('before');
  next();
});

app.get('/', function(req, res, next){
  calls.push('GET /')
  next();
});

app.use(function(req, res, next){
  calls.push('after');
  res.end();
});

request(app)
.get('/')
.end(function(res){
  calls.should.eql(['before', 'GET /', 'after'])
  done();
})

should allow escaped regexp.

var app = express();

app.get('/user/\\d+', function(req, res){
  res.end('woot');
});

request(app)
.get('/user/10')
.end(function(res){
  res.statusCode.should.equal(200);
  request(app)
  .get('/user/tj')
  .expect(404, done);
});

should allow literal ".".

var app = express();

app.get('/api/users/:from..:to', function(req, res){
  var from = req.params.from
    , to = req.params.to;

  res.end('users from ' + from + ' to ' + to);
});

request(app)
.get('/api/users/1..50')
.expect('users from 1 to 50', done);
## methods supported should include GET.
var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include POST.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include PUT.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include HEAD.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include DELETE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include OPTIONS.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include TRACE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include COPY.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include LOCK.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include MKCOL.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include MOVE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include PROPFIND.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include PROPPATCH.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include UNLOCK.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include REPORT.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include MKACTIVITY.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include CHECKOUT.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include MERGE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include M-SEARCH.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include NOTIFY.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include SUBSCRIBE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include UNSUBSCRIBE.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);

should include PATCH.

var app = express();
var calls = [];

app[method]('/foo', function(req, res){
  if ('head' == method) {
    res.end();
  } else {
    res.end(method);
  }
});

request(app)
[method]('/foo')
.expect('head' == method ? '' : method, done);
## when given a regexp should match the pathname only.
var app = express();

app.get(/^\/user\/[0-9]+$/, function(req, res){
  res.end('user');
});

request(app)
.get('/user/12?foo=bar')
.expect('user', done);

should populate req.params with the captures.

var app = express();

app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function(req, res){
  var id = req.params.shift()
    , op = req.params.shift();
  res.end(op + 'ing user ' + id);
});

request(app)
.get('/user/10/edit')
.expect('editing user 10', done);
## when given an array should match all paths in the array.
			var app = express();
			
			app.get(['/one', '/two'], function(req, res){
				res.end('works');
			});
			
			request(app)
			.get('/one')
			.expect('works', function() {
				request(app)
				.get('/two')
				.expect('works', done);
			});
## case sensitivity should be disabled by default.
var app = express();

app.get('/user', function(req, res){
  res.end('tj');
});

request(app)
.get('/USER')
.expect('tj', done);
### when "case sensitive routing" is enabled should match identical casing.
var app = express();

app.enable('case sensitive routing');

app.get('/uSer', function(req, res){
  res.end('tj');
});

request(app)
.get('/uSer')
.expect('tj', done);

should not match otherwise.

var app = express();

app.enable('case sensitive routing');

app.get('/uSer', function(req, res){
  res.end('tj');
});

request(app)
.get('/user')
.expect(404, done);
## trailing slashes should be optional by default.
var app = express();

app.get('/user', function(req, res){
  res.end('tj');
});

request(app)
.get('/user/')
.expect('tj', done);
### when "strict routing" is enabled should match trailing slashes.
var app = express();

app.enable('strict routing');

app.get('/user/', function(req, res){
  res.end('tj');
});

request(app)
.get('/user/')
.expect('tj', done);

should match no slashes.

var app = express();

app.enable('strict routing');

app.get('/user', function(req, res){
  res.end('tj');
});

request(app)
.get('/user')
.expect('tj', done);

should fail when omitting the trailing slash.

var app = express();

app.enable('strict routing');

app.get('/user/', function(req, res){
  res.end('tj');
});

request(app)
.get('/user')
.expect(404, done);

should fail when adding the trailing slash.

var app = express();

app.enable('strict routing');

app.get('/user', function(req, res){
  res.end('tj');
});

request(app)
.get('/user/')
.expect(404, done);
## * should denote a greedy capture group.
var app = express();

app.get('/user/*.json', function(req, res){
  res.end(req.params[0]);
});

request(app)
.get('/user/tj.json')
.expect('tj', done);

should work with several.

var app = express();

app.get('/api/*.*', function(req, res){
  var resource = req.params.shift()
    , format = req.params.shift();
  res.end(resource + ' as ' + format);
});

request(app)
.get('/api/users/0.json')
.expect('users/0 as json', done);

should allow naming.

var app = express();

app.get('/api/:resource(*)', function(req, res){
  var resource = req.params.resource;
  res.end(resource);
});

request(app)
.get('/api/users/0.json')
.expect('users/0.json', done);

should span multiple segments.

var app = express();

app.get('/file/*', function(req, res){
  res.end(req.params[0]);
});

request(app)
.get('/file/javascripts/jquery.js')
.expect('javascripts/jquery.js', done);

should be optional.

var app = express();

app.get('/file/*', function(req, res){
  res.end(req.params[0]);
});

request(app)
.get('/file/')
.expect('', done);

should require a preceeding /.

var app = express();

app.get('/file/*', function(req, res){
  res.end(req.params[0]);
});

request(app)
.get('/file')
.expect(404, done);
## :name should denote a capture group.
var app = express();

app.get('/user/:user', function(req, res){
  res.end(req.params.user);
});

request(app)
.get('/user/tj')
.expect('tj', done);

should match a single segment only.

var app = express();

app.get('/user/:user', function(req, res){
  res.end(req.params.user);
});

request(app)
.get('/user/tj/edit')
.expect(404, done);

should allow several capture groups.

var app = express();

app.get('/user/:user/:op', function(req, res){
  res.end(req.params.op + 'ing ' + req.params.user);
});

request(app)
.get('/user/tj/edit')
.expect('editing tj', done);
## :name? should denote an optional capture group.
var app = express();

app.get('/user/:user/:op?', function(req, res){
  var op = req.params.op || 'view';
  res.end(op + 'ing ' + req.params.user);
});

request(app)
.get('/user/tj')
.expect('viewing tj', done);

should populate the capture group.

var app = express();

app.get('/user/:user/:op?', function(req, res){
  var op = req.params.op || 'view';
  res.end(op + 'ing ' + req.params.user);
});

request(app)
.get('/user/tj/edit')
.expect('editing tj', done);
## .:name should denote a format.
var app = express();

app.get('/:name.:format', function(req, res){
  res.end(req.params.name + ' as ' + req.params.format);
});

request(app)
.get('/foo.json')
.expect('foo as json', function(){
  request(app)
  .get('/foo')
  .expect(404, done);
});
## .:name? should denote an optional format.
var app = express();

app.get('/:name.:format?', function(req, res){
  res.end(req.params.name + ' as ' + (req.params.format || 'html'));
});

request(app)
.get('/foo')
.expect('foo as html', function(){
  request(app)
  .get('/foo.json')
  .expect('foo as json', done);
});
## when next() is called should continue lookup.
var app = express()
  , calls = [];

app.get('/foo/:bar?', function(req, res, next){
  calls.push('/foo/:bar?');
  next();
});

app.get('/bar', function(req, res){
  assert(0);
});

app.get('/foo', function(req, res, next){
  calls.push('/foo');
  next();
});

app.get('/foo', function(req, res, next){
  calls.push('/foo 2');
  res.end('done');
});

request(app)
.get('/foo')
.expect('done', function(){
  calls.should.eql(['/foo/:bar?', '/foo', '/foo 2']);
  done();
})
## when next(err) is called should break out of app.router.
var app = express()
  , calls = [];

app.get('/foo/:bar?', function(req, res, next){
  calls.push('/foo/:bar?');
  next();
});

app.get('/bar', function(req, res){
  assert(0);
});

app.get('/foo', function(req, res, next){
  calls.push('/foo');
  next(new Error('fail'));
});

app.get('/foo', function(req, res, next){
  assert(0);
});

app.use(function(err, req, res, next){
  res.end(err.message);
})

request(app)
.get('/foo')
.expect('fail', function(){
  calls.should.eql(['/foo/:bar?', '/foo']);
  done();
})
# app should emit "mount" when mounted.
var blog = express()
  , app = express();

blog.on('mount', function(arg){
  arg.should.equal(app);
  done();
});

app.use(blog);
## .use(app) should mount the app.
var blog = express()
  , app = express();

blog.get('/blog', function(req, res){
  res.end('blog');
});

app.use(blog);

request(app)
.get('/blog')
.expect('blog', done);

should support mount-points.

var blog = express()
  , forum = express()
  , app = express();

blog.get('/', function(req, res){
  res.end('blog');
});

forum.get('/', function(req, res){
  res.end('forum');
});

app.use('/blog', blog);
app.use('/forum', forum);

request(app)
.get('/blog')
.expect('blog', function(){
  request(app)
  .get('/forum')
  .expect('forum', done);
});

should set the child's .parent.

var blog = express()
  , app = express();

app.use('/blog', blog);
blog.parent.should.equal(app);
# config ## .configure() should execute in order as defined.
var app = express();
var calls = [];

app.configure(function(){
  calls.push('all');
});

app.configure('test', function(){
  calls.push('test');
});

app.configure(function(){
  calls.push('all 2');
});

app.configure('test', function(){
  calls.push('test 2');
});

calls.should.eql(['all', 'test', 'all 2', 'test 2'])
### when no env is given should always execute.
var app = express();
var calls = [];

app.configure(function(){
  calls.push('all');
});

app.configure('test', function(){
  calls.push('test');
});

app.configure('test', function(){
  calls.push('test 2');
});

calls.should.eql(['all', 'test', 'test 2'])
### when an env is given should only execute the matching env.
var app = express();
var calls = [];

app.set('env', 'development');

app.configure('development', function(){
  calls.push('dev');
});

app.configure('test', function(){
  calls.push('test');
});

calls.should.eql(['dev']);
### when several envs are given should execute when matching one.
var app = express();
var calls = [];

app.set('env', 'development');

app.configure('development', function(){
  calls.push('dev');
});

app.configure('test', 'development', function(){
  calls.push('dev 2');
});

app.configure('development', 'test', function(){
  calls.push('dev 3');
});

app.configure('test', function(){
  calls.push('dev 3');
});

calls.should.eql(['dev', 'dev 2', 'dev 3']);
# config ## .set() should set a value.
var app = express();
app.set('foo', 'bar').should.equal(app);

should return the app when undefined.

var app = express();
app.set('foo', undefined).should.equal(app);
## .get() should return undefined when unset.
var app = express();
assert(undefined === app.get('foo'));

should otherwise return the value.

var app = express();
app.set('foo', 'bar');
app.get('foo').should.equal('bar');
### when mounted should default to the parent app.
var app = express()
  , blog = express();

app.set('title', 'Express');
app.use(blog);
blog.get('title').should.equal('Express');

should given precedence to the child.

var app = express()
  , blog = express();

app.use(blog);
app.set('title', 'Express');
blog.set('title', 'Some Blog');

blog.get('title').should.equal('Some Blog');
## .enable() should set the value to true.
var app = express();
app.enable('tobi').should.equal(app);
app.get('tobi').should.be.true;
## .disable() should set the value to false.
var app = express();
app.disable('tobi').should.equal(app);
app.get('tobi').should.be.false;
## .enabled() should default to false.
var app = express();
app.enabled('foo').should.be.false;

should return true when set.

var app = express();
app.set('foo', 'bar');
app.enabled('foo').should.be.true;
## .disabled() should default to true.
var app = express();
app.disabled('foo').should.be.true;

should return false when set.

var app = express();
app.set('foo', 'bar');
app.disabled('foo').should.be.false;
# exports should have .version.
express.should.have.property('version');

should expose connect middleware.

express.should.have.property('bodyParser');
express.should.have.property('session');
express.should.have.property('static');

should expose HTTP methods.

express.methods.should.be.an.instanceof(Array);
express.methods.should.include('get');
express.methods.should.include('put');
express.methods.should.include('post');

should expose Router.

express.Router.should.be.a('function');

should expose the application prototype.

express.application.set.should.be.a('function');

should expose the request prototype.

express.request.accepts.should.be.a('function');

should expose the response prototype.

express.response.send.should.be.a('function');

should permit modifying the .application prototype.

express.application.foo = function(){ return 'bar'; };
express().foo().should.equal('bar');

should permit modifying the .request prototype.

express.request.foo = function(){ return 'bar'; };
var app = express();

app.use(function(req, res, next){
  res.end(req.foo());
});

request(app)
.get('/')
.expect('bar', done);

should permit modifying the .response prototype.

express.response.foo = function(){ this.send('bar'); };
var app = express();

app.use(function(req, res, next){
  res.foo();
});

request(app)
.get('/')
.expect('bar', done);
# throw after .end() should fail gracefully.
var app = express();

app.get('/', function(req, res){
  res.end('yay');
  throw new Error('boom');
});

request(app)
.get('/')
.end(function(res){
  res.should.have.status(200);
  res.body.should.equal('yay');
  done();
});
# req ## .accepted should return an array of accepted media types.
var app = express();

app.use(function(req, res){
  req.accepted[0].value.should.equal('application/json');
  req.accepted[1].value.should.equal('text/html');
  res.end();
});

request(app)
.get('/')
.set('Accept', 'text/html;q=.5, application/json')
.expect(200, done);
### when Accept is not present should default to [].
var app = express();

app.use(function(req, res){
  req.accepted.should.have.length(0);
  res.end();
});

request(app)
.get('/')
.expect(200, done);
# req ## .acceptedCharsets should return an array of accepted charsets.
var app = express();

app.use(function(req, res){
  req.acceptedCharsets[0].should.equal('unicode-1-1');
  req.acceptedCharsets[1].should.equal('iso-8859-5');
  res.end();
});

request(app)
.get('/')
.set('Accept-Charset', 'iso-8859-5;q=.2, unicode-1-1;q=0.8')
.expect(200, done);
### when Accept-Charset is not present should default to [].
var app = express();

app.use(function(req, res){
  req.acceptedCharsets.should.have.length(0);
  res.end();
});

request(app)
.get('/')
.expect(200, done);
# req ## .acceptedLanguages should return an array of accepted languages.
var app = express();

app.use(function(req, res){
  req.acceptedLanguages[0].should.equal('en-us');
  req.acceptedLanguages[1].should.equal('en');
  res.end();
});

request(app)
.get('/')
.set('Accept-Language', 'en;q=.5, en-us')
.expect(200, done);
### when Accept-Language is not present should default to [].
var app = express();

app.use(function(req, res){
  req.acceptedLanguages.should.have.length(0);
  res.end();
});

request(app)
.get('/')
.expect(200, done);
# req ## .accepts(type) should return true when Accept is not present.
var app = express();

app.use(function(req, res, next){
  res.end(req.accepts('json') ? 'yes' : 'no');
});

request(app)
.get('/')
.expect('yes', done);

should return true when present.

var app = express();

app.use(function(req, res, next){
  res.end(req.accepts('json') ? 'yes' : 'no');
});

request(app)
.get('/')
.set('Accept', 'application/json')
.expect('yes', done);

should return false otherwise.

var app = express();

app.use(function(req, res, next){
  res.end(req.accepts('json') ? 'yes' : 'no');
});

request(app)
.get('/')
.set('Accept', 'text/html')
.expect('no', done);
# req ## .acceptsCharset(type) ### when Accept-Charset is not present should return true.
var app = express();

app.use(function(req, res, next){
  res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
});

request(app)
.get('/')
.expect('yes', done);
### when Accept-Charset is not present should return true when present.
var app = express();

app.use(function(req, res, next){
  res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
});

request(app)
.get('/')
.set('Accept-Charset', 'foo, bar, utf-8')
.expect('yes', done);

should return false otherwise.

var app = express();

app.use(function(req, res, next){
  res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
});

request(app)
.get('/')
.set('Accept-Charset', 'foo, bar')
.expect('no', done);
# req ## .cookies should expose cookie data.
var app = express();

app.use(express.cookieParser());

app.use(function(req, res){
  res.end(req.cookies.name + ' ' + req.cookies.species);
});

request(app)
.get('/')
.set('Cookie', 'name=tobi; species=ferret')
.end(function(res){
  res.body.should.equal('tobi ferret');
  done();
})

should parse JSON cookies.

var app = express();

app.use(express.cookieParser());

app.use(function(req, res){
  res.end(req.cookies.user.name);
});

request(app)
.get('/')
.set('Cookie', 'user=j%3A%7B%22name%22%3A%22tobi%22%7D')
.end(function(res){
  res.body.should.equal('tobi');
  done();
})
# req ## .fresh should return true when the resource is not modified.
var app = express();

app.use(function(req, res){
  res.set('ETag', '12345');
  res.send(req.fresh);
});

request(app)
.get('/')
.set('If-None-Match', '12345')
.end(function(res){
  res.body.should.equal('true');
  done();
});

should return false when the resource is modified.

var app = express();

app.use(function(req, res){
  res.set('ETag', '123');
  res.send(req.fresh);
});

request(app)
.get('/')
.set('If-None-Match', '12345')
.end(function(res){
  res.body.should.equal('false');
  done();
});
# req ## .get(field) should return the header field value.
var app = express();

app.use(function(req, res){
  res.end(req.get('Content-Type'));
});

request(app)
.post('/')
.set('Content-Type', 'application/json')
.end(function(res){
  res.body.should.equal('application/json');
  done();
});

should special-case Referer.

var app = express();

app.use(function(req, res){
  res.end(req.get('Referer'));
});

request(app)
.post('/')
.set('Referrer', 'http://foobar.com')
.end(function(res){
  res.body.should.equal('http://foobar.com');
  done();
});
# req.is() should ignore charset.
req('application/json; charset=utf-8')
.is('json')
.should.be.true;
## when content-type is not present should return false.
req('')
.is('json')
.should.be.false;
## when given an extension should lookup the mime type.
req('application/json')
.is('json')
.should.be.true;

req('text/html')
.is('json')
.should.be.false;
## when given a mime type should match.
req('application/json')
.is('application/json')
.should.be.true;

req('image/jpeg')
.is('application/json')
.should.be.false;
## when given */subtype should match.
req('application/json')
.is('*/json')
.should.be.true;

req('image/jpeg')
.is('*/json')
.should.be.false;
### with a charset should match.
req('text/html; charset=utf-8')
.is('*/html')
.should.be.true;

req('text/plain; charset=utf-8')
.is('*/html')
.should.be.false;
## when given type/* should match.
req('image/png')
.is('image/*')
.should.be.true;

req('text/html')
.is('image/*')
.should.be.false;
### with a charset should match.
req('text/html; charset=utf-8')
.is('text/*')
.should.be.true;

req('something/html; charset=utf-8')
.is('text/*')
.should.be.false;
# req ## .param(name, default) should use the default value unless defined.
var app = express();

app.use(function(req, res){
  res.end(req.param('name', 'tj'));
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('tj');
  done();
})
## .param(name) should check req.query.
var app = express();

app.use(function(req, res){
  res.end(req.param('name'));
});

request(app)
.get('/?name=tj')
.end(function(res){
  res.body.should.equal('tj');
  done();
})

should check req.body.

var app = express();

app.use(express.bodyParser());

app.use(function(req, res){
  res.end(req.param('name'));
});

request(app)
.post('/')
.set('Content-Type', 'application/json')
.write('{"name":"tj"}')
.end(function(res){
  res.body.should.equal('tj');
  done();
})

should check req.params.

var app = express();

app.get('/user/:name', function(req, res){
  res.end(req.param('name'));
});

request(app)
.get('/user/tj')
.end(function(res){
  res.body.should.equal('tj');
  done();
})
# req ## .path should return the parsed pathname.
var app = express();

app.use(function(req, res){
  res.end(req.path);
});

request(app)
.get('/login?redirect=/post/1/comments')
.end(function(res){
  res.body.should.equal('/login');
  done();
})
# req ## .protocol should return the protocol string.
var app = express();

app.use(function(req, res){
  res.end(req.protocol);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('http');
  done();
})
### when "trust proxy" is enabled should respect X-Forwarded-Proto.
var app = express();

app.enable('trust proxy');

app.use(function(req, res){
  res.end(req.protocol);
});

request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.end(function(res){
  res.body.should.equal('https');
  done();
})

should default to http.

var app = express();

app.enable('trust proxy');

app.use(function(req, res){
  res.end(req.protocol);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('http');
  done();
})
### when "trust proxy" is disabled should ignore X-Forwarded-Proto.
var app = express();

app.use(function(req, res){
  res.end(req.protocol);
});

request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.end(function(res){
  res.body.should.equal('http');
  done();
})
# req ## .query should default to {}.
var app = express();

app.use(function(req, res){
  req.query.should.eql({});
  res.end();
});

request(app)
.get('/')
.end(function(res){
  done();
});

should contain the parsed query-string.

var app = express();

app.use(function(req, res){
  req.query.should.eql({ user: { name: 'tj' }});
  res.end();
});

request(app)
.get('/?user[name]=tj')
.end(function(res){
  done();
});
# req ## .route should be the executed Route.
var app = express();

app.get('/user/:id/:op?', function(req, res, next){
  req.route.method.should.equal('get');
  req.route.path.should.equal('/user/:id/:op?');
  next();
});

app.get('/user/:id/edit', function(req, res){
  req.route.method.should.equal('get');
  req.route.path.should.equal('/user/:id/edit');
  res.end();
});

request(app)
.get('/user/12/edit')
.expect(200, done);
# req ## .signedCookies should unsign cookies.
var app = express();

app.use(express.cookieParser('foo bar baz'));

app.use(function(req, res){
  req.cookies.should.not.have.property('name');
  res.end(req.signedCookies.name);
});

request(app)
.get('/')
.set('Cookie', 'name=tobi.2HDdGQqJ6jQU1S9dagggYDPaxGE')
.end(function(res){
  res.body.should.equal('tobi');
  done();
})

should parse JSON cookies.

var app = express();

app.use(express.cookieParser('foo bar baz'));

app.use(function(req, res){
  req.cookies.should.not.have.property('user');
  res.end(req.signedCookies.user.name);
});

request(app)
.get('/')
.set('Cookie', 'user=j%3A%7B%22name%22%3A%22tobi%22%7D.aEbp4PGZo63zMX%2FcIMSn2M9pvms')
.end(function(res){
  res.body.should.equal('tobi');
  done();
})
### when signature is invalid should unsign cookies.
var app = express();

app.use(express.cookieParser('foo bar baz'));

app.use(function(req, res){
  req.signedCookies.should.not.have.property('name');
  res.end(req.cookies.name);
});

request(app)
.get('/')
.set('Cookie', 'name=tobi.2HDdGQqJ6jQU1S9dagasdfasdf')
.end(function(res){
  res.body.should.equal('tobi.2HDdGQqJ6jQU1S9dagasdfasdf');
  done();
})
# req ## .stale should return false when the resource is not modified.
var app = express();

app.use(function(req, res){
  res.set('ETag', '12345');
  res.send(req.stale);
});

request(app)
.get('/')
.set('If-None-Match', '12345')
.end(function(res){
  res.body.should.equal('false');
  done();
});

should return true when the resource is modified.

var app = express();

app.use(function(req, res){
  res.set('ETag', '123');
  res.send(req.stale);
});

request(app)
.get('/')
.set('If-None-Match', '12345')
.end(function(res){
  res.body.should.equal('true');
  done();
});
# req ## .subdomains ### when present should return an array.
var app = express();

app.use(function(req, res){
  res.send(req.subdomains);
});

request(app)
.get('/')
.set('Host', 'tobi.ferrets.example.com')
.end(function(res){
  res.body.should.equal('["ferrets","tobi"]');
  done();
})
### otherwise should return an empty array.
var app = express();

app.use(function(req, res){
  res.send(req.subdomains);
});

request(app)
.get('/')
.set('Host', 'example.com')
.end(function(res){
  res.body.should.equal('[]');
  done();
})
# req ## .xhr should return true when X-Requested-With is xmlhttprequest.
var app = express();

app.use(function(req, res){
  req.xhr.should.be.true;
  res.end();
});

request(app)
.get('/')
.set('X-Requested-With', 'xmlhttprequest')
.end(function(res){
  done();
})

should case-insensitive.

var app = express();

app.use(function(req, res){
  req.xhr.should.be.true;
  res.end();
});

request(app)
.get('/')
.set('X-Requested-With', 'XMLHttpRequest')
.end(function(res){
  done();
})

should return false otherwise.

var app = express();

app.use(function(req, res){
  req.xhr.should.be.false;
  res.end();
});

request(app)
.get('/')
.set('X-Requested-With', 'blahblah')
.end(function(res){
  done();
})

should return false when not present.

var app = express();

app.use(function(req, res){
  req.xhr.should.be.false;
  res.end();
});

request(app)
.get('/')
.end(function(res){
  done();
})
# res ## .attachment() should Content-Disposition to attachment.
var app = express();

app.use(function(req, res){
  res.attachment().send('foo');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-disposition', 'attachment');
  done();
})
## .attachment(filename) should add the filename param.
var app = express();

app.use(function(req, res){
  res.attachment('/path/to/image.png');
  res.send('foo');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-disposition', 'attachment; filename="image.png"');
  done();
})

should set the Content-Type.

var app = express();

app.use(function(req, res){
  res.attachment('/path/to/image.png');
  res.send('foo');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'image/png');
  done();
})
# res ## .cache(type) should set Cache-Control.
var app = express();

app.use(function(req, res){
  res.cache('public').end('whoop');
});

request(app)
.get('/')
.end(function(res){
  res.headers['cache-control'].should.equal('public');
  res.body.should.equal('whoop');
  done();
})
### maxAge option should accept milliseconds.
var app = express();

app.use(function(req, res){
  res.cache('private', { maxAge: 60 * 1000 }).end();
});

request(app)
.get('/')
.end(function(res){
  res.headers['cache-control'].should.equal('private, max-age=60');
  done();
})
# res ## .charset should add the charset param to Content-Type.
var app = express();

app.use(function(req, res){
  res.charset = 'utf-8';
  res.set('Content-Type', 'text/x-foo');
  res.end(res.get('Content-Type'));
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('text/x-foo; charset=utf-8');
  done();
})

should take precedence over res.send() defaults.

var app = express();

app.use(function(req, res){
  res.charset = 'whoop';
  res.send('hey');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'text/html; charset=whoop');
  done();
})
# res ## .clearCookie(name) should set a cookie passed expiry.
var app = express();

app.use(function(req, res){
  res.clearCookie('sid').end();
});

request(app)
.get('/')
.end(function(res){
  var val = 'sid=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
  res.headers['set-cookie'].should.eql([val]);
  done();
})
## .clearCookie(name, options) should set the given params.
var app = express();

app.use(function(req, res){
  res.clearCookie('sid', { path: '/admin' }).end();
});

request(app)
.get('/')
.end(function(res){
  var val = 'sid=; path=/admin; expires=Thu, 01 Jan 1970 00:00:00 GMT';
  res.headers['set-cookie'].should.eql([val]);
  done();
})
# res ## .cookie(name, object) should generate a JSON cookie.
var app = express();

app.use(function(req, res){
  res.cookie('user', { name: 'tobi' }).end();
});

request(app)
.get('/')
.end(function(res){
  var val = ['user=j%3A%7B%22name%22%3A%22tobi%22%7D; path=/'];
  res.headers['set-cookie'].should.eql(val);
  done();
})
## .cookie(name, string) should set a cookie.
var app = express();

app.use(function(req, res){
  res.cookie('name', 'tobi').end();
});

request(app)
.get('/')
.end(function(res){
  var val = ['name=tobi; path=/'];
  res.headers['set-cookie'].should.eql(val);
  done();
})

should allow multiple calls.

var app = express();

app.use(function(req, res){
  res.cookie('name', 'tobi');
  res.cookie('age', 1);
  res.end();
});

request(app)
.get('/')
.end(function(res){
  var val = ['name=tobi; path=/', 'age=1; path=/'];
  res.headers['set-cookie'].should.eql(val);
  done();
})
## .cookie(name, string, options) should set params.
var app = express();

app.use(function(req, res){
  res.cookie('name', 'tobi', { httpOnly: true, secure: true });
  res.end();
});

request(app)
.get('/')
.end(function(res){
  var val = ['name=tobi; path=/; httpOnly; secure'];
  res.headers['set-cookie'].should.eql(val);
  done();
})
### maxAge should set relative expires.
var app = express();

app.use(function(req, res){
  res.cookie('name', 'tobi', { maxAge: 1000 });
  res.end();
});

request(app)
.get('/')
.end(function(res){
  res.headers['set-cookie'][0].should.not.include('Thu, 01 Jan 1970 00:00:01 GMT');
  done();
})
# req ## .format(obj) ### with canonicalized mime types should utilize qvalues in negotiation.
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/json, */*; q=.1')
.expect('{"message":"hey"}', done);

should allow wildcard type/subtypes.

request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/*, */*; q=.1')
.expect('{"message":"hey"}', done);

should default the Content-Type.

request(app)
.get('/')
.set('Accept', 'text/html; q=.5, text/plain')
.end(function(res){
  res.headers['content-type'].should.equal('text/plain');
  res.body.should.equal('hey');
  done();
});
#### when Accept is not present should invoke the first callback.
request(app)
.get('/')
.expect('hey', done);
#### when no match is made should should respond with 406 not acceptable.
request(app)
.get('/')
.set('Accept', 'foo/bar')
.end(function(res){
  res.should.have.status(406);
  res.body.should.equal('Supports: text/plain, text/html, application/json');
  done();
});
### with extnames should utilize qvalues in negotiation.
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/json, */*; q=.1')
.expect('{"message":"hey"}', done);

should allow wildcard type/subtypes.

request(app)
.get('/')
.set('Accept', 'text/html; q=.5, application/*, */*; q=.1')
.expect('{"message":"hey"}', done);

should default the Content-Type.

request(app)
.get('/')
.set('Accept', 'text/html; q=.5, text/plain')
.end(function(res){
  res.headers['content-type'].should.equal('text/plain');
  res.body.should.equal('hey');
  done();
});
#### when Accept is not present should invoke the first callback.
request(app)
.get('/')
.expect('hey', done);
#### when no match is made should should respond with 406 not acceptable.
request(app)
.get('/')
.set('Accept', 'foo/bar')
.end(function(res){
  res.should.have.status(406);
  res.body.should.equal('Supports: text/plain, text/html, application/json');
  done();
});
# res ## .get(field) should get the response header field.
var app = express();

app.use(function(req, res){
  res.setHeader('Content-Type', 'text/x-foo');
  res.end(res.get('Content-Type'));
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('text/x-foo');
  done();
})
# res ## .json(object) ### when given primitives should respond with json.
var app = express();

app.use(function(req, res){
  res.json(null);
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
  res.body.should.equal('null');
  done();
})
### when given an object should respond with json.
var app = express();

app.use(function(req, res){
  res.json({ name: 'tobi' });
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
  res.body.should.equal('{"name":"tobi"}');
  done();
})
### "json replacer" setting should be passed to JSON.stringify().
var app = express();

app.set('json replacer', function(key, val){
  return '_' == key[0]
    ? undefined
    : val;
});

app.use(function(req, res){
  res.json({ name: 'tobi', _id: 12345 });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('{"name":"tobi"}');
  done();
});
### "json spaces" setting should default to 2 in development.
process.env.NODE_ENV = 'development';
var app = express();
app.get('json spaces').should.equal(2);
process.env.NODE_ENV = 'test';

should be undefined otherwise.

var app = express();
assert(undefined === app.get('json spaces'));

should be passed to JSON.stringify().

var app = express();

app.set('json spaces', 2);

app.use(function(req, res){
  res.json({ name: 'tobi', age: 2 });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('{\n  "name": "tobi",\n  "age": 2\n}');
  done();
});
## .json(status, object) should respond with json and set the .statusCode.
var app = express();

app.use(function(req, res){
  res.json(201, { id: 1 });
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(201);
  res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
  res.body.should.equal('{"id":1}');
  done();
})
# res ## .locals(obj) should merge locals.
var app = express();

app.use(function(req, res){
  Object.keys(res.locals).should.eql([]);
  res.locals({ user: 'tobi', age: 1 });
  res.locals.user.should.equal('tobi');
  res.locals.age.should.equal(1);
  res.end();
});

request(app)
.get('/')
.end(function(res){
  done();
})
# res ## .redirect(url) should respect X-Forwarded-Proto when "trust proxy" is enabled.
var app = express();

app.enable('trust proxy');

app.use(function(req, res){
  res.redirect('/login');
});

request(app)
.get('/')
.set('Host', 'example.com')
.set('X-Forwarded-Proto', 'https')
.end(function(res){
  res.statusCode.should.equal(302);
  res.headers.should.have.property('location', 'https://example.com/login');
  done();
})

should default to a 302 redirect.

var app = express();

app.use(function(req, res){
  res.redirect('http://google.com');
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(302);
  res.headers.should.have.property('location', 'http://google.com');
  done();
})
### with leading / should construct host-relative urls.
var app = express();

app.use(function(req, res){
  res.redirect('/login');
});

request(app)
.get('/')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/login');
  done();
})
### with leading ./ should construct path-relative urls.
var app = express();

app.use(function(req, res){
  res.redirect('./edit');
});

request(app)
.get('/post/1')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/post/1/./edit');
  done();
})
### with leading ../ should construct path-relative urls.
var app = express();

app.use(function(req, res){
  res.redirect('../new');
});

request(app)
.get('/post/1')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/post/1/../new');
  done();
})
### without leading / should construct mount-point relative urls.
var app = express();

app.use(function(req, res){
  res.redirect('login');
});

request(app)
.get('/')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/login');
  done();
})
### when mounted #### deeply should respect the mount-point.
var app = express()
  , blog = express()
  , admin = express();

admin.use(function(req, res){
  res.redirect('login');
});

app.use('/blog', blog);
blog.use('/admin', admin);

request(app)
.get('/blog/admin')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/blog/admin/login');
  done();
})
#### omitting leading / should respect the mount-point.
var app = express()
  , admin = express();

admin.use(function(req, res){
  res.redirect('admin/login');
});

app.use('/blog', admin);

request(app)
.get('/blog')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/blog/admin/login');
  done();
})
#### providing leading / should ignore mount-point.
var app = express()
  , admin = express();

admin.use(function(req, res){
  res.redirect('/admin/login');
});

app.use('/blog', admin);

request(app)
.get('/blog')
.set('Host', 'example.com')
.end(function(res){
  res.headers.should.have.property('location', 'http://example.com/admin/login');
  done();
})
## .redirect(status, url) should set the response status.
var app = express();

app.use(function(req, res){
  res.redirect(303, 'http://google.com');
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(303);
  res.headers.should.have.property('location', 'http://google.com');
  done();
})
## when the request method is HEAD should ignore the body.
var app = express();

app.use(function(req, res){
  res.redirect('http://google.com');
});

request(app)
.head('/')
.end(function(res){
  res.headers.should.have.property('location', 'http://google.com');
  res.body.should.equal('');
  done();
})
## when accepting html should respond with html.
var app = express();

app.use(function(req, res){
  res.redirect('http://google.com');
});

request(app)
.get('/')
.set('Accept', 'text/html')
.end(function(res){
  res.headers.should.have.property('location', 'http://google.com');
  res.body.should.equal('<p>Moved Temporarily. Redirecting to <a href="http://google.com">http://google.com</a></p>');
  done();
})
## when accepting text should respond with text.
var app = express();

app.use(function(req, res){
  res.redirect('http://google.com');
});

request(app)
.get('/')
.set('Accept', 'text/plain, */*')
.end(function(res){
  res.headers.should.have.property('location', 'http://google.com');
  res.body.should.equal('Moved Temporarily. Redirecting to http://google.com');
  done();
})
# res ## .render(name) should support absolute paths.
var app = express();
  
app.locals.user = { name: 'tobi' };

app.use(function(req, res){
  res.render(__dirname + '/fixtures/user.jade');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should support absolute paths with "view engine".

var app = express();
  
app.locals.user = { name: 'tobi' };
app.set('view engine', 'jade');

app.use(function(req, res){
  res.render(__dirname + '/fixtures/user');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should expose app.locals.

var app = express();
  
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };

app.use(function(req, res){
  res.render('user.jade');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should support index..

var app = express();
  
app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');

app.use(function(req, res){
  res.render('blog/post');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<h1>blog post</h1>');
  done();
});
### when an error occurs should next(err).
var app = express();
  
app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  res.render('user.jade');
});

app.use(function(err, req, res, next){
  res.end(err.message);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.match(/user is not defined/);
  done();
});
### when "view engine" is given should render the template.
var app = express();
  
app.set('view engine', 'jade');
app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  res.render('email');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>This is an email</p>');
  done();
});
## .render(name, option) should render the template.
var app = express();
  
app.set('views', __dirname + '/fixtures');
  
var user = { name: 'tobi' };

app.use(function(req, res){
  res.render('user.jade', { user: user });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should expose app.locals.

var app = express();
    
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };

app.use(function(req, res){
  res.render('user.jade', {});
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should expose res.locals.

var app = express();
    
app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  res.locals.user = { name: 'tobi' };
  res.render('user.jade', {});
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>tobi</p>');
  done();
});

should give precedence to res.locals over app.locals.

var app = express();
    
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };

app.use(function(req, res){
  res.locals.user = { name: 'jane' };
  res.render('user.jade', {});
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>jane</p>');
  done();
});

should give precedence to res.render() locals over res.locals.

var app = express();
    
app.set('views', __dirname + '/fixtures');
var jane = { name: 'jane' };
    
app.use(function(req, res){
  res.locals.user = { name: 'tobi' };
  res.render('user.jade', { user: jane });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>jane</p>');
  done();
});

should give precedence to res.render() locals over app.locals.

var app = express();
    
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };
    
app.use(function(req, res){
  res.render('user.jade', { user: jane });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>jane</p>');
  done();
});
## .render(name, options, fn) should pass the resulting string.
var app = express();

app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  var tobi = { name: 'tobi' };
  res.render('user.jade', { user: tobi }, function(err, html){
    html = html.replace('tobi', 'loki');
    res.end(html);
  });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>loki</p>');
  done();
});
## .render(name, fn) should pass the resulting string.
var app = express();

app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  res.locals.user = { name: 'tobi' };
  res.render('user.jade', function(err, html){
    html = html.replace('tobi', 'loki');
    res.end(html);
  });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>loki</p>');
  done();
});
### when an error occurs should pass it to the callback.
var app = express();

app.set('views', __dirname + '/fixtures');

app.use(function(req, res){
  res.render('user.jade', function(err){
    res.end(err.message);
  });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.match(/is not defined/);
  done();
});
# res ## .send(null) should set body to "".
var app = express();

app.use(function(req, res){
  res.send(null);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('');
  done();
})
## .send(undefined) should set body to "".
var app = express();

app.use(function(req, res){
  res.send(undefined);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('');
  done();
})
## .send(code) should set .statusCode.
var app = express();

app.use(function(req, res){
  res.send(201).should.equal(res);
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('Created');
  res.statusCode.should.equal(201);
  done();
})
## .send(code, body) should set .statusCode and body.
var app = express();

app.use(function(req, res){
  res.send(201, 'Created :)');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('Created :)');
  res.statusCode.should.equal(201);
  done();
})
## .send(String) should send as html.
var app = express();

app.use(function(req, res){
  res.send('<p>hey</p>');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'text/html; charset=utf-8');
  res.body.should.equal('<p>hey</p>');
  res.statusCode.should.equal(200);
  done();
})

should not override Content-Type.

var app = express();

app.use(function(req, res){
  res.set('Content-Type', 'text/plain').send('hey');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'text/plain');
  res.body.should.equal('hey');
  res.statusCode.should.equal(200);
  done();
})
## .send(Buffer) should send as octet-stream.
var app = express();

app.use(function(req, res){
  res.send(new Buffer('hello'));
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'application/octet-stream');
  res.body.should.equal('hello');
  res.statusCode.should.equal(200);
  done();
})

should not override Content-Type.

var app = express();

app.use(function(req, res){
  res.set('Content-Type', 'text/plain').send(new Buffer('hey'));
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'text/plain');
  res.body.should.equal('hey');
  res.statusCode.should.equal(200);
  done();
})
## .send(Object) should send as application/json.
var app = express();

app.use(function(req, res){
  res.send({ name: 'tobi' });
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
  res.body.should.equal('{"name":"tobi"}');
  done();
})
## when the request method is HEAD should ignore the body.
var app = express();

app.use(function(req, res){
  res.send('yay');
});

request(app)
.head('/')
.end(function(res){
  res.body.should.equal('');
  done();
})
## when .statusCode is 204 should strip Content-* fields & body.
var app = express();

app.use(function(req, res){
  res.status(204).send('foo');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.not.have.property('content-type');
  res.headers.should.not.have.property('content-length');
  res.body.should.equal('');
  done();
})
## when .statusCode is 304 should strip Content-* fields & body.
var app = express();

app.use(function(req, res){
  res.status(304).send('foo');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.not.have.property('content-type');
  res.headers.should.not.have.property('content-length');
  res.body.should.equal('');
  done();
})
# res ## .sendfile(path, fn) should invoke the callback when complete.
var app = express()
  , calls = 0;

app.use(function(req, res){
  res.sendfile('test/fixtures/user.html', function(err){
    assert(!err);
    ++calls;
  });
});

request(app)
.get('/')
.end(function(res){
  calls.should.equal(1);
  res.statusCode.should.equal(200);
  done();
});

should invoke the callback on 404.

var app = express()
  , calls = 0;

app.use(function(req, res){
  res.sendfile('test/fixtures/nope.html', function(err){
    assert(!res.headerSent);
    ++calls;
    res.send(err.message);
  });
});

request(app)
.get('/')
.end(function(res){
  calls.should.equal(1);
  res.body.should.equal('Not Found');
  res.statusCode.should.equal(200);
  done();
});

should not override manual content-types.

var app = express();

app.use(function(req, res){
  res.contentType('txt');
  res.sendfile('test/fixtures/user.html');
});

request(app)
.get('/')
.end(function(res){
  res.should.have.header('content-type', 'text/plain');
  done();
});

should invoke the callback on 403.

var app = express()
  , calls = 0;

app.use(function(req, res){
  res.sendfile('test/fixtures/foo/../user.html', function(err){
    assert(!res.headerSent);
    ++calls;
    res.send(err.message);
  });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('Forbidden');
  res.statusCode.should.equal(200);
  calls.should.equal(1);
  done();
});
## .sendfile(path) ### with an absolute path should transfer the file.
var app = express();

app.use(function(req, res){
  res.sendfile(__dirname + '/fixtures/user.html');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>{{user.name}}</p>');
  res.headers.should.have.property('content-type', 'text/html; charset=UTF-8');
  done();
});
### with a relative path should transfer the file.
var app = express();

app.use(function(req, res){
  res.sendfile('test/fixtures/user.html');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>{{user.name}}</p>');
  res.headers.should.have.property('content-type', 'text/html; charset=UTF-8');
  done();
});

should serve relative to "root".

var app = express();

app.use(function(req, res){
  res.sendfile('user.html', { root: 'test/fixtures/' });
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('<p>{{user.name}}</p>');
  res.headers.should.have.property('content-type', 'text/html; charset=UTF-8');
  done();
});

should consider ../ malicious when "root" is not set.

var app = express();

app.use(function(req, res){
  res.sendfile('test/fixtures/foo/../user.html');
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(403);
  done();
});

should allow ../ when "root" is set.

var app = express();

app.use(function(req, res){
  res.sendfile('foo/../user.html', { root: 'test/fixtures' });
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(200);
  done();
});

should disallow requesting out of "root".

var app = express();

app.use(function(req, res){
  res.sendfile('foo/../../user.html', { root: 'test/fixtures' });
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(403);
  done();
});

should next(404) when not found.

var app = express()
  , calls = 0;

app.use(function(req, res){
  res.sendfile('user.html');
});

app.use(function(req, res){
  assert(0, 'this should not be called');
});

app.use(function(err, req, res, next){
  ++calls;
  next(err);
});

request(app)
.get('/')
.end(function(res){
  res.statusCode.should.equal(404);
  calls.should.equal(1);
  done();
});
#### with non-GET should still serve.
var app = express()
   , calls = 0;

 app.use(function(req, res){
   res.sendfile(__dirname + '/fixtures/name.txt');
 });


 request(app)
 .get('/')
 .expect('tobi', done);
# res ## .set(field, value) should set the response header field.
var app = express();

app.use(function(req, res){
  res.set('Content-Type', 'text/x-foo').end();
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'text/x-foo');
  done();
})
## .set(object) should set multiple fields.
var app = express();

app.use(function(req, res){
  res.set({
    'X-Foo': 'bar',
    'X-Bar': 'baz'
  }).end();
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('x-foo', 'bar');
  res.headers.should.have.property('x-bar', 'baz');
  done();
})
# res ## .signedCook(name, object) should generate a signed JSON cookie.
var app = express();

app.use(express.cookieParser('foo bar baz'));

app.use(function(req, res){
  res.signedCookie('user', { name: 'tobi' }).end();
});
  
request(app)
.get('/')
.end(function(res){
  var val = ['user=j%3A%7B%22name%22%3A%22tobi%22%7D.aEbp4PGZo63zMX%2FcIMSn2M9pvms; path=/'];
  res.headers['set-cookie'].should.eql(val);
  done();
})
## .signedCookie(name, string) should set a signed cookie.
var app = express();

app.use(express.cookieParser('foo bar baz'));

app.use(function(req, res){
  res.signedCookie('name', 'tobi').end();
});
  
request(app)
.get('/')
.end(function(res){
  var val = ['name=tobi.2HDdGQqJ6jQU1S9dagggYDPaxGE; path=/'];
  res.headers['set-cookie'].should.eql(val);
  done();
})
# res ## .status(code) should set the response .statusCode.
var app = express();

app.use(function(req, res){
  res.status(201).end('Created');
});

request(app)
.get('/')
.end(function(res){
  res.body.should.equal('Created');
  res.statusCode.should.equal(201);
  done();
})
# res ## .type(str) should set the Content-Type based on a filename.
var app = express();

app.use(function(req, res){
  res.type('foo.js').end('var name = "tj";');
});

request(app)
.get('/')
.end(function(res){
  res.headers.should.have.property('content-type', 'application/javascript');
  done();
})
# Router ## .match(req, i) should match based on index.
router.route('get', '/foo', function(){});
router.route('get', '/foob?', function(){});
router.route('get', '/bar', function(){});
var req = { method: 'GET', url: '/foo?bar=baz' };

var route = router.match(req, 0);
route.constructor.name.should.equal('Route');
route.method.should.equal('get');
route.path.should.equal('/foo');

var route = router.match(req, 1);
req._route_index.should.equal(1);
route.path.should.equal('/foob?');

var route = router.match(req, 2);
assert(!route);

req.url = '/bar';
var route = router.match(req);
route.path.should.equal('/bar');
## .middleware should dispatch.
router.route('get', '/foo', function(req, res){
  res.send('foo');
});

app.use(router.middleware);

request(app)
.get('/foo')
.expect('foo', done);
# utils.isAbsolute() should support windows.
assert(utils.isAbsolute('c:\\'));
assert(!utils.isAbsolute(':\\'));

should unices.

assert(utils.isAbsolute('/foo/bar'));
assert(!utils.isAbsolute('foo/bar'));
# utils.flatten(arr) should flatten an array.
var arr = ['one', ['two', ['three', 'four'], 'five']];
utils.flatten(arr)
  .should.eql(['one', 'two', 'three', 'four', 'five']);
# utils.escape(html) should escape html entities.
utils.escape('<script>foo & "bar"')
  .should.equal('&lt;script&gt;foo &amp; &quot;bar&quot;')
# utils.parseQuality(str) should default quality to 1.
utils.parseQuality('text/html')
  .should.eql([{ value: 'text/html', quality: 1 }]);

should parse qvalues.

utils.parseQuality('text/html; q=0.5')
  .should.eql([{ value: 'text/html', quality: 0.5 }]);

utils.parseQuality('text/html; q=.2')
  .should.eql([{ value: 'text/html', quality: 0.2 }]);

should work with messed up whitespace.

utils.parseQuality('text/html   ;  q =   .2')
  .should.eql([{ value: 'text/html', quality: 0.2 }]);

should work with multiples.

var str = 'da, en;q=.5, en-gb;q=.8';
var arr = utils.parseQuality(str);
arr[0].value.should.equal('da');
arr[1].value.should.equal('en-gb');
arr[2].value.should.equal('en');

should sort by quality.

var str = 'text/plain;q=.2, application/json, text/html;q=0.5';
var arr = utils.parseQuality(str);
arr[0].value.should.equal('application/json');
arr[1].value.should.equal('text/html');
arr[2].value.should.equal('text/plain');

should exclude those with a quality of 0.

var str = 'text/plain;q=.2, application/json, text/html;q=0';
var arr = utils.parseQuality(str);
arr.should.have.length(2);
# utils.parseAccept(str) should provide .type.
var arr = utils.parseAccept('text/html');
arr[0].type.should.equal('text');

should provide .subtype.

var arr = utils.parseAccept('text/html');
arr[0].subtype.should.equal('html');
# utils.accepts(type, str) ## when a string is not given should return true.
utils.accepts('text/html')
  .should.be.true;
## when a string is empty should return true.
utils.accepts('text/html', '')
  .should.be.true;
## when */* is given should return true.
utils.accepts('text/html', 'text/plain, */*')
  .should.be.true;
## when accepting type/subtype should return true when present.
utils.accepts('text/html', 'text/plain, text/html')
  .should.be.true;

should return false otherwise.

utils.accepts('text/html', 'text/plain, application/json')
  .should.be.false;
## when accepting */subtype should return true when present.
utils.accepts('text/html', 'text/*')
  .should.be.true;

should return false otherwise.

utils.accepts('text/html', 'image/*')
  .should.be.false;
## when accepting type/* should return true when present.
utils.accepts('text/html', '*/html')
  .should.be.true;

should return false otherwise.

utils.accepts('text/html', '*/json')
  .should.be.false;
## when an extension is given should return true when present.
utils.accepts('html', 'text/html, application/json')
  .should.be.true;

should return false otherwise.

utils.accepts('html', 'text/plain, application/json')
  .should.be.false;

should support *.

utils.accepts('html', 'text/*')
  .should.be.true;

utils.accepts('html', '*/html')
  .should.be.true;