diff --git a/lib/request.js b/lib/request.js index 4491c19..2cb7447 100644 --- a/lib/request.js +++ b/lib/request.js @@ -249,7 +249,7 @@ module.exports = { get idempotent() { var methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']; - return ~methods.indexOf(this.method); + return !!~methods.indexOf(this.method); }, /** diff --git a/test/request/fresh.js b/test/request/fresh.js index 1609aa2..34e112d 100644 --- a/test/request/fresh.js +++ b/test/request/fresh.js @@ -2,6 +2,14 @@ var context = require('../context'); describe('ctx.fresh', function(){ + describe('the request method is not GET and HEAD', function (){ + it('should return false', function (){ + var ctx = context(); + ctx.req.method = 'POST'; + ctx.fresh.should.be.false; + }) + }) + describe('the response is non-2xx', function(){ it('should return false', function(){ var ctx = context(); @@ -36,4 +44,4 @@ describe('ctx.fresh', function(){ }) }) }) -}) \ No newline at end of file +}) diff --git a/test/request/get.js b/test/request/get.js index e3d76c9..263c808 100644 --- a/test/request/get.js +++ b/test/request/get.js @@ -5,8 +5,11 @@ describe('ctx.get(name)', function(){ it('should return the field value', function(){ var ctx = context(); ctx.req.headers.host = 'http://google.com'; + ctx.req.headers.referer = 'http://google.com'; ctx.get('HOST').should.equal('http://google.com'); ctx.get('Host').should.equal('http://google.com'); ctx.get('host').should.equal('http://google.com'); + ctx.get('referer').should.equal('http://google.com'); + ctx.get('referrer').should.equal('http://google.com'); }) -}) \ No newline at end of file +}) diff --git a/test/request/host.js b/test/request/host.js index 2bbeb0c..d378759 100644 --- a/test/request/host.js +++ b/test/request/host.js @@ -1,4 +1,5 @@ +var assert = require('assert'); var request = require('../context').request; describe('req.host', function(){ @@ -8,6 +9,13 @@ describe('req.host', function(){ req.host.should.equal('foo.com:3000'); }) + describe('with no host present', function(){ + it('should return null', function(){ + var req = request(); + assert(null == req.host); + }) + }) + describe('when X-Forwarded-Host is present', function(){ describe('and proxy is not trusted', function(){ it('should be ignored', function(){ diff --git a/test/request/hostname.js b/test/request/hostname.js index e60b95b..a2af5b6 100644 --- a/test/request/hostname.js +++ b/test/request/hostname.js @@ -1,4 +1,5 @@ +var assert = require('assert'); var request = require('../context').request; describe('req.hostname', function(){ @@ -8,6 +9,13 @@ describe('req.hostname', function(){ req.hostname.should.equal('foo.com'); }) + describe('with no host present', function(){ + it('should return null', function(){ + var req = request(); + assert(null == req.hostname); + }) + }) + describe('when X-Forwarded-Host is present', function(){ describe('and proxy is not trusted', function(){ it('should be ignored', function(){ diff --git a/test/request/idempotent.js b/test/request/idempotent.js new file mode 100644 index 0000000..773dfa6 --- /dev/null +++ b/test/request/idempotent.js @@ -0,0 +1,23 @@ + +var request = require('../context').request; + +describe('ctx.idempotent', function(){ + describe('when the request method is idempotent', function (){ + it('should return true', function (){ + ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'].forEach(check); + function check(method) { + var req = request(); + req.method = method; + req.idempotent.should.equal(true); + } + }) + }) + + describe('when the request method is not idempotent', function(){ + it('should return false', function (){ + var req = request(); + req.method = 'POST'; + req.idempotent.should.equal(false); + }) + }) +}) diff --git a/test/request/inspect.js b/test/request/inspect.js new file mode 100644 index 0000000..f707fa3 --- /dev/null +++ b/test/request/inspect.js @@ -0,0 +1,29 @@ + +var assert = require('assert'); +var request = require('../context').request; + +describe('req.inspect()', function(){ + describe('with no request.req present', function(){ + it('should return null', function(){ + var req = request(); + req.method = 'GET'; + delete req.req; + assert(null == req.inspect()); + }) + }) + + it('should return a json representation', function(){ + var req = request(); + req.method = 'GET'; + req.url = 'example.com'; + req.header.host = 'example.com'; + + req.inspect().should.eql({ + method: 'GET', + url: 'example.com', + header: { + host: 'example.com' + } + }); + }) +}) diff --git a/test/request/ip.js b/test/request/ip.js new file mode 100644 index 0000000..4fa6255 --- /dev/null +++ b/test/request/ip.js @@ -0,0 +1,22 @@ + +var request = require('../context').request; + +describe('req.ip', function(){ + describe('with req.ips present', function(){ + it('should return req.ips[0]', function(){ + var req = request(); + req.app.proxy = true; + req.header['x-forwarded-for'] = '127.0.0.1'; + req.socket.remoteAddress = '127.0.0.2'; + req.ip.should.equal('127.0.0.1'); + }) + }) + + describe('with no req.ips present', function(){ + it('should return req.socket.removeAddress', function(){ + var req = request(); + req.socket.remoteAddress = '127.0.0.2'; + req.ip.should.equal('127.0.0.2'); + }) + }) +}) diff --git a/test/request/ips.js b/test/request/ips.js new file mode 100644 index 0000000..801d9cd --- /dev/null +++ b/test/request/ips.js @@ -0,0 +1,24 @@ + +var request = require('../context').request; + +describe('req.ips', function(){ + describe('when X-Forwarded-For is present', function(){ + describe('and proxy is not trusted', function(){ + it('should be ignored', function(){ + var req = request(); + req.app.proxy = false; + req.header['x-forwarded-for'] = '127.0.0.1,127.0.0.2'; + req.ips.should.eql([]); + }) + }) + + describe('and proxy is trusted', function(){ + it('should be used', function(){ + var req = request(); + req.app.proxy = true; + req.header['x-forwarded-for'] = '127.0.0.1,127.0.0.2'; + req.ips.should.eql(['127.0.0.1', '127.0.0.2']); + }) + }) + }) +}) diff --git a/test/request/is.js b/test/request/is.js index 9d83e3b..7e937d3 100644 --- a/test/request/is.js +++ b/test/request/is.js @@ -76,6 +76,11 @@ describe('ctx.is(type)', function(){ ctx.is('image/*', 'image/png').should.equal('image/png'); ctx.is('image/png', 'image/*').should.equal('image/png'); + ctx.is(['text/*', 'image/*']).should.equal('image/png'); + ctx.is(['image/*', 'text/*']).should.equal('image/png'); + ctx.is(['image/*', 'image/png']).should.equal('image/png'); + ctx.is(['image/png', 'image/*']).should.equal('image/png'); + ctx.is('jpeg').should.be.false; ctx.is('.jpeg').should.be.false; ctx.is('text/*', 'application/*').should.be.false; @@ -94,4 +99,4 @@ describe('ctx.is(type)', function(){ ctx.is('urlencoded', 'json').should.equal('urlencoded'); }) }) -}) \ No newline at end of file +}) diff --git a/test/request/length.js b/test/request/length.js new file mode 100644 index 0000000..83920d0 --- /dev/null +++ b/test/request/length.js @@ -0,0 +1,16 @@ + +var assert = require('assert'); +var request = require('../context').request; + +describe('ctx.length', function(){ + it('should return length in content-length', function(){ + var req = request(); + req.header['content-length'] = '10'; + req.length.should.equal(10); + }) + + describe('with no content-length present', function(){ + var req = request(); + assert(null == req.length); + }) +}) diff --git a/test/request/protocol.js b/test/request/protocol.js index 341ae57..dd24f95 100644 --- a/test/request/protocol.js +++ b/test/request/protocol.js @@ -27,6 +27,16 @@ describe('req.protocol', function(){ req.header['x-forwarded-proto'] = 'https, http'; req.protocol.should.equal('https'); }) + + describe('and X-Forwarded-Proto is empty', function(){ + it('should return "http"', function(){ + var req = request(); + req.app.proxy = true; + req.req.socket = {}; + req.header['x-forwarded-proto'] = ''; + req.protocol.should.equal('http'); + }) + }) }) describe('and proxy is not trusted', function(){ @@ -38,4 +48,4 @@ describe('req.protocol', function(){ }) }) }) -}) \ No newline at end of file +}) diff --git a/test/request/subdomains.js b/test/request/subdomains.js new file mode 100644 index 0000000..df2a0a6 --- /dev/null +++ b/test/request/subdomains.js @@ -0,0 +1,19 @@ + +var request = require('../context').request; + +describe('req.subdomains', function(){ + it('should return subdomain array', function(){ + var req = request(); + req.header.host = 'tobi.ferrets.example.com'; + req.app.subdomainOffset = 2; + req.subdomains.should.eql(['ferrets', 'tobi']); + + req.app.subdomainOffset = 3; + req.subdomains.should.eql(['tobi']); + }) + + describe('with no host present', function(){ + var req = request(); + req.subdomains.should.eql([]); + }) +}) diff --git a/test/request/type.js b/test/request/type.js new file mode 100644 index 0000000..0468f17 --- /dev/null +++ b/test/request/type.js @@ -0,0 +1,16 @@ + +var assert = require('assert'); +var request = require('../context').request; + +describe('req.type', function(){ + it('should return type void of parameters', function(){ + var req = request(); + req.header['content-type'] = 'text/html; charset=utf-8'; + req.type.should.equal('text/html'); + }) + + describe('with no host present', function(){ + var req = request(); + assert(null == req.type); + }) +}) diff --git a/test/response/etag.js b/test/response/etag.js index a634a80..eb709c4 100644 --- a/test/response/etag.js +++ b/test/response/etag.js @@ -1,7 +1,7 @@ var response = require('../context').response; -describe('res.etag', function(){ +describe('res.etag=', function(){ it('should not modify an etag with quotes', function(){ var res = response(); res.etag = '"asdf"'; @@ -19,4 +19,12 @@ describe('res.etag', function(){ res.etag = 'asdf'; res.header.etag.should.equal('"asdf"'); }) -}) \ No newline at end of file +}) + +describe('res.etag', function(){ + it('should return etag', function(){ + var res = response(); + res.etag = '"asdf"'; + res.etag.should.equal('"asdf"'); + }) +}) diff --git a/test/response/inspect.js b/test/response/inspect.js new file mode 100644 index 0000000..5170718 --- /dev/null +++ b/test/response/inspect.js @@ -0,0 +1,29 @@ + +var assert = require('assert'); +var response = require('../context').response; + +describe('res.inspect()', function(){ + describe('with no response.res present', function(){ + it('should return null', function(){ + var res = response(); + res.body = 'hello'; + delete res.res; + assert(null == res.inspect()); + }) + }) + + it('should return a json representation', function(){ + var res = response(); + res.body = 'hello'; + + res.inspect().should.eql({ + body: 'hello', + status: 200, + string: 'OK', + header: { + 'content-length': '5', + 'content-type': 'text/plain; charset=utf-8' + } + }); + }) +}) diff --git a/test/response/is.js b/test/response/is.js index 68427cf..57d4ab0 100644 --- a/test/response/is.js +++ b/test/response/is.js @@ -60,6 +60,11 @@ describe('response.is(type)', function(){ res.is('image/*', 'image/png').should.equal('image/png'); res.is('image/png', 'image/*').should.equal('image/png'); + res.is(['text/*', 'image/*']).should.equal('image/png'); + res.is(['image/*', 'text/*']).should.equal('image/png'); + res.is(['image/*', 'image/png']).should.equal('image/png'); + res.is(['image/png', 'image/*']).should.equal('image/png'); + res.is('jpeg').should.be.false; res.is('.jpeg').should.be.false; res.is('text/*', 'application/*').should.be.false; diff --git a/test/response/set.js b/test/response/set.js index 64df231..6eb846f 100644 --- a/test/response/set.js +++ b/test/response/set.js @@ -13,6 +13,12 @@ describe('ctx.set(name, val)', function(){ ctx.set('x-foo', 5); ctx.response.header['x-foo'].should.equal('5'); }) + + it('should set a field value of array', function(){ + var ctx = context(); + ctx.set('x-foo', ['foo', 'bar']); + ctx.response.header['x-foo'].should.eql([ 'foo', 'bar' ]); + }) }) describe('ctx.set(object)', function(){ @@ -27,4 +33,4 @@ describe('ctx.set(object)', function(){ ctx.response.header.foo.should.equal('1'); ctx.response.header.bar.should.equal('2'); }) -}) \ No newline at end of file +})