better test coverage
This commit is contained in:
parent
53a763beab
commit
ff81206c4a
|
@ -3,4 +3,4 @@ node_js:
|
|||
- "0.10"
|
||||
- "0.11"
|
||||
before_install: npm install -g npm
|
||||
script: npm test
|
||||
script: npm run coverage
|
|
@ -4,6 +4,7 @@ node-fetch
|
|||
|
||||
[![npm version][npm-image]][npm-url]
|
||||
[![build status][travis-image]][travis-url]
|
||||
[![coverage status][coveralls-image]][coveralls-url]
|
||||
|
||||
A light-weight module that brings `window.fetch` to node.js
|
||||
|
||||
|
@ -57,3 +58,5 @@ Thanks to [github/fetch](https://github.com/github/fetch) for providing a solid
|
|||
[npm-url]: https://www.npmjs.com/package/node-fetch
|
||||
[travis-image]: https://img.shields.io/travis/bitinn/node-fetch.svg?style=flat-square
|
||||
[travis-url]: https://travis-ci.org/bitinn/node-fetch
|
||||
[coveralls-image]: https://img.shields.io/coveralls/bitinn/node-fetch.svg?style=flat-square
|
||||
[coveralls-url]: https://coveralls.io/r/bitinn/node-fetch
|
||||
|
|
3
index.js
3
index.js
|
@ -66,7 +66,7 @@ function Fetch(url, opts) {
|
|||
var options = {
|
||||
hostname: uri.hostname
|
||||
, port: uri.port
|
||||
, path: uri.path || '/'
|
||||
, path: uri.path
|
||||
, auth: uri.auth
|
||||
, method: opts.method || 'GET'
|
||||
, headers: opts.headers || {}
|
||||
|
@ -156,6 +156,7 @@ function Fetch(url, opts) {
|
|||
url: uri.href
|
||||
, status: res.statusCode
|
||||
, headers: headers
|
||||
, size: options.size
|
||||
});
|
||||
|
||||
resolve(output);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
var http = require('http');
|
||||
var stream = require('stream');
|
||||
var convert = require('encoding').convert;
|
||||
|
||||
module.exports = Response;
|
||||
|
@ -24,8 +23,9 @@ function Response(body, opts) {
|
|||
this.status = opts.status;
|
||||
this.statusText = http.STATUS_CODES[this.status];
|
||||
this.headers = opts.headers;
|
||||
this.body = body.pipe(new stream.PassThrough());
|
||||
this.body = body;
|
||||
this.bodyUsed = false;
|
||||
this.size = opts.size;
|
||||
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,10 @@ Response.prototype._decode = function() {
|
|||
|
||||
return new Response.Promise(function(resolve, reject) {
|
||||
self.body.on('data', function(chunk) {
|
||||
if (self._abort) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk === null) {
|
||||
return;
|
||||
}
|
||||
|
@ -80,7 +84,6 @@ Response.prototype._decode = function() {
|
|||
if (self.size && self._bytes > self.size) {
|
||||
self._abort = true;
|
||||
reject(new Error('content size at ' + self.url + ' over limit: ' + self.size));
|
||||
self.body.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -137,7 +140,7 @@ Response.prototype._convert = function(encoding) {
|
|||
charset = res.pop();
|
||||
|
||||
// prevent decode issues when sites use incorrect encoding
|
||||
// see: https://hsivonen.fi/encoding-menu/
|
||||
// ref: https://hsivonen.fi/encoding-menu/
|
||||
if (charset === 'gb2312' || charset === 'gbk') {
|
||||
charset = 'gb18030';
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
"description": "A light-weight module that brings window.fetch to node.js",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "mocha test/test.js"
|
||||
"test": "mocha test/test.js",
|
||||
"report": "istanbul cover _mocha -- -R spec test/test.js",
|
||||
"coverage": "istanbul cover _mocha --report lcovonly -- -R spec test/test.js && cat ./coverage/lcov.info | coveralls"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -25,6 +27,8 @@
|
|||
"bluebird": "^2.9.1",
|
||||
"chai": "^1.10.0",
|
||||
"chai-as-promised": "^4.1.1",
|
||||
"coveralls": "^2.11.2",
|
||||
"istanbul": "^0.3.5",
|
||||
"mocha": "^2.1.0",
|
||||
"promise": "^6.1.0",
|
||||
"resumer": "0.0.0"
|
||||
|
|
|
@ -3,6 +3,7 @@ var http = require('http');
|
|||
var parse = require('url').parse;
|
||||
var zlib = require('zlib');
|
||||
var stream = require('stream');
|
||||
var convert = require('encoding').convert;
|
||||
|
||||
module.exports = TestServer;
|
||||
|
||||
|
@ -53,6 +54,17 @@ TestServer.prototype.router = function(req, res) {
|
|||
}));
|
||||
}
|
||||
|
||||
if (p === '/long') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
setTimeout(function() {
|
||||
res.write('test');
|
||||
}, 50);
|
||||
setTimeout(function() {
|
||||
res.end('test');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
if (p === '/gzip') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
|
@ -79,6 +91,30 @@ TestServer.prototype.router = function(req, res) {
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
if (p === '/cookie') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Set-Cookie', ['a=1', 'b=1']);
|
||||
res.end('cookie');
|
||||
}
|
||||
|
||||
if (p === '/encoding/gbk') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end(convert('<meta charset="gbk"><div>中文</div>', 'gbk'));
|
||||
}
|
||||
|
||||
if (p === '/encoding/gb2312') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end(convert('<meta http-equiv="Content-Type" content="text/html; charset=gb2312"><div>中文</div>', 'gb2312'));
|
||||
}
|
||||
|
||||
if (p === '/encoding/shift-jis') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/html; charset=Shift-JIS');
|
||||
res.end(convert('<div>日本語</div>', 'Shift_JIS'));
|
||||
}
|
||||
|
||||
if (p === '/redirect/301') {
|
||||
res.statusCode = 301;
|
||||
res.setHeader('Location', '/inspect');
|
||||
|
@ -115,6 +151,28 @@ TestServer.prototype.router = function(req, res) {
|
|||
res.end();
|
||||
}
|
||||
|
||||
if (p === '/error/redirect') {
|
||||
res.statusCode = 301;
|
||||
//res.setHeader('Location', '/inspect');
|
||||
res.end();
|
||||
}
|
||||
|
||||
if (p === '/error/400') {
|
||||
res.statusCode = 400;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end('client error');
|
||||
}
|
||||
|
||||
if (p === '/error/500') {
|
||||
res.statusCode = 500;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end('server error');
|
||||
}
|
||||
|
||||
if (p === '/error/reset') {
|
||||
res.destroy();
|
||||
}
|
||||
|
||||
if (p === '/inspect') {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
|
|
170
test/test.js
170
test/test.js
|
@ -189,14 +189,60 @@ describe('node-fetch', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should obey maximum redirect limit', function() {
|
||||
it('should follow redirect chain', function() {
|
||||
url = base + '/redirect/chain';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.url).to.equal(base + '/inspect');
|
||||
expect(res.status).to.equal(200);
|
||||
});
|
||||
});
|
||||
|
||||
it('should obey maximum redirect', function() {
|
||||
url = base + '/redirect/chain';
|
||||
opts = {
|
||||
follow: 1
|
||||
};
|
||||
}
|
||||
return expect(fetch(url, opts)).to.eventually.be.rejectedWith(Error);
|
||||
});
|
||||
|
||||
it('should reject broken redirect', function() {
|
||||
url = base + '/error/redirect';
|
||||
return expect(fetch(url)).to.eventually.be.rejectedWith(Error);
|
||||
});
|
||||
|
||||
it('should handle client-error response', function() {
|
||||
url = base + '/error/400';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.headers.get('content-type')).to.equal('text/plain');
|
||||
expect(res.status).to.equal(400);
|
||||
expect(res.statusText).to.equal('Bad Request');
|
||||
return res.text().then(function(result) {
|
||||
expect(res.bodyUsed).to.be.true;
|
||||
expect(result).to.be.a('string');
|
||||
expect(result).to.equal('client error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle server-error response', function() {
|
||||
url = base + '/error/500';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.headers.get('content-type')).to.equal('text/plain');
|
||||
expect(res.status).to.equal(500);
|
||||
expect(res.statusText).to.equal('Internal Server Error');
|
||||
return res.text().then(function(result) {
|
||||
expect(res.bodyUsed).to.be.true;
|
||||
expect(result).to.be.a('string');
|
||||
expect(result).to.equal('server error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle network-error response', function() {
|
||||
url = base + '/error/reset';
|
||||
return expect(fetch(url)).to.eventually.be.rejectedWith(Error);
|
||||
});
|
||||
|
||||
it('should decompress gzip response', function() {
|
||||
url = base + '/gzip';
|
||||
return fetch(url).then(function(res) {
|
||||
|
@ -281,4 +327,124 @@ describe('node-fetch', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should allow PUT request', function() {
|
||||
url = base + '/inspect';
|
||||
opts = {
|
||||
method: 'PUT'
|
||||
, body: 'a=1'
|
||||
};
|
||||
return fetch(url, opts).then(function(res) {
|
||||
return res.json();
|
||||
}).then(function(res) {
|
||||
expect(res.method).to.equal('PUT');
|
||||
expect(res.body).to.equal('a=1');
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow DELETE request', function() {
|
||||
url = base + '/inspect';
|
||||
opts = {
|
||||
method: 'DELETE'
|
||||
};
|
||||
return fetch(url, opts).then(function(res) {
|
||||
return res.json();
|
||||
}).then(function(res) {
|
||||
expect(res.method).to.equal('DELETE');
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow HEAD request', function() {
|
||||
url = base + '/hello';
|
||||
opts = {
|
||||
method: 'HEAD'
|
||||
|
||||
};
|
||||
return fetch(url, opts).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
expect(res.statusText).to.equal('OK');
|
||||
expect(res.headers.get('content-type')).to.equal('text/plain');
|
||||
expect(res.body).to.be.an.instanceof(stream.Transform);
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject decoding body twice', function() {
|
||||
url = base + '/plain';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.headers.get('content-type')).to.equal('text/plain');
|
||||
return res.text().then(function(result) {
|
||||
expect(res.bodyUsed).to.be.true;
|
||||
return expect(res.text()).to.eventually.be.rejectedWith(Error);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support maximum response size', function() {
|
||||
url = base + '/long';
|
||||
opts = {
|
||||
size: 1
|
||||
};
|
||||
return fetch(url, opts).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
expect(res.headers.get('content-type')).to.equal('text/plain');
|
||||
return expect(res.text()).to.eventually.be.rejectedWith(Error);
|
||||
});
|
||||
});
|
||||
|
||||
it('should support encoding decode, conte-type detect', function() {
|
||||
url = base + '/encoding/shift-jis';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
return res.text().then(function(result) {
|
||||
expect(result).to.equal('<div>日本語</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support encoding decode, html5 detect', function() {
|
||||
url = base + '/encoding/gbk';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
return res.text().then(function(result) {
|
||||
expect(result).to.equal('<meta charset="gbk"><div>中文</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support encoding decode, html4 detect', function() {
|
||||
url = base + '/encoding/gb2312';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
return res.text().then(function(result) {
|
||||
expect(result).to.equal('<meta http-equiv="Content-Type" content="text/html; charset=gb2312"><div>中文</div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow get all responses of a header', function() {
|
||||
url = base + '/cookie';
|
||||
return fetch(url).then(function(res) {
|
||||
expect(res.headers.getAll('set-cookie')).to.deep.equal(['a=1', 'b=1']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow deleting header', function() {
|
||||
url = base + '/cookie';
|
||||
return fetch(url).then(function(res) {
|
||||
res.headers.delete('set-cookie');
|
||||
expect(res.headers.get('set-cookie')).to.be.null;
|
||||
expect(res.headers.getAll('set-cookie')).to.be.empty;
|
||||
});
|
||||
});
|
||||
|
||||
it('should support https request', function() {
|
||||
this.timeout(5000);
|
||||
url = 'https://github.com/';
|
||||
opts = {
|
||||
method: 'HEAD'
|
||||
};
|
||||
return fetch(url, opts).then(function(res) {
|
||||
expect(res.status).to.equal(200);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue