diff options
Diffstat (limited to 'utilities/hash_script/node_modules/node-fetch/test')
3 files changed, 1828 insertions, 0 deletions
diff --git a/utilities/hash_script/node_modules/node-fetch/test/dummy.txt b/utilities/hash_script/node_modules/node-fetch/test/dummy.txt new file mode 100644 index 0000000..5ca5191 --- /dev/null +++ b/utilities/hash_script/node_modules/node-fetch/test/dummy.txt @@ -0,0 +1 @@ +i am a dummy
\ No newline at end of file diff --git a/utilities/hash_script/node_modules/node-fetch/test/server.js b/utilities/hash_script/node_modules/node-fetch/test/server.js new file mode 100644 index 0000000..5b1b3b9 --- /dev/null +++ b/utilities/hash_script/node_modules/node-fetch/test/server.js @@ -0,0 +1,340 @@ + +var http = require('http'); +var parse = require('url').parse; +var zlib = require('zlib'); +var stream = require('stream'); +var convert = require('encoding').convert; +var Multipart = require('parted').multipart; + +module.exports = TestServer; + +function TestServer() { + this.server = http.createServer(this.router); + this.port = 30001; + this.hostname = 'localhost'; + // node 8 default keepalive timeout is 5000ms + // make it shorter here as we want to close server quickly at the end of tests + this.server.keepAliveTimeout = 1000; + this.server.on('error', function(err) { + console.log(err.stack); + }); + this.server.on('connection', function(socket) { + socket.setTimeout(1500); + }); +} + +TestServer.prototype.start = function(cb) { + this.server.listen(this.port, this.hostname, cb); +} + +TestServer.prototype.stop = function(cb) { + this.server.close(cb); +} + +TestServer.prototype.router = function(req, res) { + + var p = parse(req.url).pathname; + + if (p === '/hello') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('world'); + } + + if (p === '/plain') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('text'); + } + + if (p === '/options') { + res.statusCode = 200; + res.setHeader('Allow', 'GET, HEAD, OPTIONS'); + res.end('hello world'); + } + + if (p === '/html') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + res.end('<html></html>'); + } + + if (p === '/json') { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ + name: 'value' + })); + } + + if (p === '/gzip') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Encoding', 'gzip'); + zlib.gzip('hello world', function(err, buffer) { + res.end(buffer); + }); + } + + if (p === '/deflate') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Encoding', 'deflate'); + zlib.deflate('hello world', function(err, buffer) { + res.end(buffer); + }); + } + + if (p === '/deflate-raw') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Encoding', 'deflate'); + zlib.deflateRaw('hello world', function(err, buffer) { + res.end(buffer); + }); + } + + if (p === '/sdch') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Encoding', 'sdch'); + res.end('fake sdch string'); + } + + if (p === '/invalid-content-encoding') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.setHeader('Content-Encoding', 'gzip'); + res.end('fake gzip string'); + } + + if (p === '/timeout') { + setTimeout(function() { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('text'); + }, 1000); + } + + if (p === '/slow') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.write('test'); + setTimeout(function() { + res.end('test'); + }, 1000); + } + + if (p === '/cookie') { + res.statusCode = 200; + res.setHeader('Set-Cookie', ['a=1', 'b=1']); + res.end('cookie'); + } + + if (p === '/size/chunk') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + setTimeout(function() { + res.write('test'); + }, 50); + setTimeout(function() { + res.end('test'); + }, 100); + } + + if (p === '/size/long') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('testtest'); + } + + 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 === '/encoding/euc-jp') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/xml'); + res.end(convert('<?xml version="1.0" encoding="EUC-JP"?><title>日本語</title>', 'EUC-JP')); + } + + if (p === '/encoding/utf8') { + res.statusCode = 200; + res.end('中文'); + } + + if (p === '/encoding/order1') { + res.statusCode = 200; + res.setHeader('Content-Type', 'charset=gbk; text/plain'); + res.end(convert('中文', 'gbk')); + } + + if (p === '/encoding/order2') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain; charset=gbk; qs=1'); + res.end(convert('中文', 'gbk')); + } + + if (p === '/encoding/chunked') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + res.setHeader('Transfer-Encoding', 'chunked'); + var padding = 'a'; + for (var i = 0; i < 10; i++) { + res.write(padding); + } + res.end(convert('<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" /><div>日本語</div>', 'Shift_JIS')); + } + + if (p === '/encoding/invalid') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + res.setHeader('Transfer-Encoding', 'chunked'); + // because node v0.12 doesn't have str.repeat + var padding = new Array(120 + 1).join('a'); + for (var i = 0; i < 10; i++) { + res.write(padding); + } + res.end(convert('中文', 'gbk')); + } + + if (p === '/redirect/301') { + res.statusCode = 301; + res.setHeader('Location', '/inspect'); + res.end(); + } + + if (p === '/redirect/302') { + res.statusCode = 302; + res.setHeader('Location', '/inspect'); + res.end(); + } + + if (p === '/redirect/303') { + res.statusCode = 303; + res.setHeader('Location', '/inspect'); + res.end(); + } + + if (p === '/redirect/307') { + res.statusCode = 307; + res.setHeader('Location', '/inspect'); + res.end(); + } + + if (p === '/redirect/308') { + res.statusCode = 308; + res.setHeader('Location', '/inspect'); + res.end(); + } + + if (p === '/redirect/chain') { + res.statusCode = 301; + res.setHeader('Location', '/redirect/301'); + 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/404') { + res.statusCode = 404; + res.setHeader('Content-Encoding', 'gzip'); + res.end(); + } + + 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 === '/error/json') { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end('invalid json'); + } + + if (p === '/no-content') { + res.statusCode = 204; + res.end(); + } + + if (p === '/no-content/gzip') { + res.statusCode = 204; + res.setHeader('Content-Encoding', 'gzip'); + res.end(); + } + + if (p === '/not-modified') { + res.statusCode = 304; + res.end(); + } + + if (p === '/not-modified/gzip') { + res.statusCode = 304; + res.setHeader('Content-Encoding', 'gzip'); + res.end(); + } + + if (p === '/inspect') { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + var body = ''; + req.on('data', function(c) { body += c }); + req.on('end', function() { + res.end(JSON.stringify({ + method: req.method, + url: req.url, + headers: req.headers, + body: body + })); + }); + } + + if (p === '/multipart') { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + var parser = new Multipart(req.headers['content-type']); + var body = ''; + parser.on('part', function(field, part) { + body += field + '=' + part; + }); + parser.on('end', function() { + res.end(JSON.stringify({ + method: req.method, + url: req.url, + headers: req.headers, + body: body + })); + }); + req.pipe(parser); + } +} diff --git a/utilities/hash_script/node_modules/node-fetch/test/test.js b/utilities/hash_script/node_modules/node-fetch/test/test.js new file mode 100644 index 0000000..284b263 --- /dev/null +++ b/utilities/hash_script/node_modules/node-fetch/test/test.js @@ -0,0 +1,1487 @@ + +// test tools +var chai = require('chai'); +var cap = require('chai-as-promised'); +chai.use(cap); +var expect = chai.expect; +var bluebird = require('bluebird'); +var then = require('promise'); +var spawn = require('child_process').spawn; +var stream = require('stream'); +var resumer = require('resumer'); +var FormData = require('form-data'); +var http = require('http'); +var fs = require('fs'); + +var TestServer = require('./server'); + +// test subjects +var fetch = require('../index.js'); +var Headers = require('../lib/headers.js'); +var Response = require('../lib/response.js'); +var Request = require('../lib/request.js'); +var Body = require('../lib/body.js'); +var FetchError = require('../lib/fetch-error.js'); +// test with native promise on node 0.11, and bluebird for node 0.10 +fetch.Promise = fetch.Promise || bluebird; + +var url, opts, local, base; + +describe('node-fetch', function() { + + before(function(done) { + local = new TestServer(); + base = 'http://' + local.hostname + ':' + local.port; + local.start(done); + }); + + after(function(done) { + local.stop(done); + }); + + it('should return a promise', function() { + url = 'http://example.com/'; + var p = fetch(url); + expect(p).to.be.an.instanceof(fetch.Promise); + expect(p).to.have.property('then'); + }); + + it('should allow custom promise', function() { + url = 'http://example.com/'; + var old = fetch.Promise; + fetch.Promise = then; + expect(fetch(url)).to.be.an.instanceof(then); + expect(fetch(url)).to.not.be.an.instanceof(bluebird); + fetch.Promise = old; + }); + + it('should throw error when no promise implementation are found', function() { + url = 'http://example.com/'; + var old = fetch.Promise; + fetch.Promise = undefined; + expect(function() { + fetch(url) + }).to.throw(Error); + fetch.Promise = old; + }); + + it('should expose Headers, Response and Request constructors', function() { + expect(fetch.Headers).to.equal(Headers); + expect(fetch.Response).to.equal(Response); + expect(fetch.Request).to.equal(Request); + }); + + it('should reject with error if url is protocol relative', function() { + url = '//example.com/'; + return expect(fetch(url)).to.eventually.be.rejectedWith(Error); + }); + + it('should reject with error if url is relative path', function() { + url = '/some/path'; + return expect(fetch(url)).to.eventually.be.rejectedWith(Error); + }); + + it('should reject with error if protocol is unsupported', function() { + url = 'ftp://example.com/'; + return expect(fetch(url)).to.eventually.be.rejectedWith(Error); + }); + + it('should reject with error on network failure', function() { + url = 'http://localhost:50000/'; + return expect(fetch(url)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.include({ type: 'system', code: 'ECONNREFUSED', errno: 'ECONNREFUSED' }); + }); + + it('should resolve into response', function() { + url = base + '/hello'; + return fetch(url).then(function(res) { + expect(res).to.be.an.instanceof(Response); + expect(res.headers).to.be.an.instanceof(Headers); + expect(res.body).to.be.an.instanceof(stream.Transform); + expect(res.bodyUsed).to.be.false; + + expect(res.url).to.equal(url); + expect(res.ok).to.be.true; + expect(res.status).to.equal(200); + expect(res.statusText).to.equal('OK'); + }); + }); + + it('should accept plain text response', 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; + expect(result).to.be.a('string'); + expect(result).to.equal('text'); + }); + }); + }); + + it('should accept html response (like plain text)', function() { + url = base + '/html'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/html'); + return res.text().then(function(result) { + expect(res.bodyUsed).to.be.true; + expect(result).to.be.a('string'); + expect(result).to.equal('<html></html>'); + }); + }); + }); + + it('should accept json response', function() { + url = base + '/json'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('application/json'); + return res.json().then(function(result) { + expect(res.bodyUsed).to.be.true; + expect(result).to.be.an('object'); + expect(result).to.deep.equal({ name: 'value' }); + }); + }); + }); + + it('should send request with custom headers', function() { + url = base + '/inspect'; + opts = { + headers: { 'x-custom-header': 'abc' } + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.headers['x-custom-header']).to.equal('abc'); + }); + }); + + it('should accept headers instance', function() { + url = base + '/inspect'; + opts = { + headers: new Headers({ 'x-custom-header': 'abc' }) + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.headers['x-custom-header']).to.equal('abc'); + }); + }); + + it('should accept custom host header', function() { + url = base + '/inspect'; + opts = { + headers: { + host: 'example.com' + } + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.headers['host']).to.equal('example.com'); + }); + }); + + it('should follow redirect code 301', function() { + url = base + '/redirect/301'; + return fetch(url).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + expect(res.ok).to.be.true; + }); + }); + + it('should follow redirect code 302', function() { + url = base + '/redirect/302'; + return fetch(url).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + }); + }); + + it('should follow redirect code 303', function() { + url = base + '/redirect/303'; + return fetch(url).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + }); + }); + + it('should follow redirect code 307', function() { + url = base + '/redirect/307'; + return fetch(url).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + }); + }); + + it('should follow redirect code 308', function() { + url = base + '/redirect/308'; + return fetch(url).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + }); + }); + + 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 follow POST request redirect code 301 with GET', function() { + url = base + '/redirect/301'; + opts = { + method: 'POST' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + return res.json().then(function(result) { + expect(result.method).to.equal('GET'); + expect(result.body).to.equal(''); + }); + }); + }); + + it('should follow POST request redirect code 302 with GET', function() { + url = base + '/redirect/302'; + opts = { + method: 'POST' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + return res.json().then(function(result) { + expect(result.method).to.equal('GET'); + expect(result.body).to.equal(''); + }); + }); + }); + + it('should follow redirect code 303 with GET', function() { + url = base + '/redirect/303'; + opts = { + method: 'PUT' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + return res.json().then(function(result) { + expect(result.method).to.equal('GET'); + expect(result.body).to.equal(''); + }); + }); + }); + + it('should obey maximum redirect, reject case', function() { + url = base + '/redirect/chain'; + opts = { + follow: 1 + } + return expect(fetch(url, opts)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'max-redirect'); + }); + + it('should obey redirect chain, resolve case', function() { + url = base + '/redirect/chain'; + opts = { + follow: 2 + } + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + expect(res.status).to.equal(200); + }); + }); + + it('should allow not following redirect', function() { + url = base + '/redirect/301'; + opts = { + follow: 0 + } + return expect(fetch(url, opts)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'max-redirect'); + }); + + it('should support redirect mode, manual flag', function() { + url = base + '/redirect/301'; + opts = { + redirect: 'manual' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(url); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.equal(base + '/inspect'); + }); + }); + + it('should support redirect mode, error flag', function() { + url = base + '/redirect/301'; + opts = { + redirect: 'error' + }; + return expect(fetch(url, opts)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'no-redirect'); + }); + + it('should support redirect mode, manual flag when there is no redirect', function() { + url = base + '/hello'; + opts = { + redirect: 'manual' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(url); + expect(res.status).to.equal(200); + expect(res.headers.get('location')).to.be.null; + }); + }); + + it('should follow redirect code 301 and keep existing headers', function() { + url = base + '/redirect/301'; + opts = { + headers: new Headers({ 'x-custom-header': 'abc' }) + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(base + '/inspect'); + return res.json(); + }).then(function(res) { + expect(res.headers['x-custom-header']).to.equal('abc'); + }); + }); + + it('should reject broken redirect', function() { + url = base + '/error/redirect'; + return expect(fetch(url)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'invalid-redirect'); + }); + + it('should not reject broken redirect under manual redirect', function() { + url = base + '/error/redirect'; + opts = { + redirect: 'manual' + }; + return fetch(url, opts).then(function(res) { + expect(res.url).to.equal(url); + expect(res.status).to.equal(301); + expect(res.headers.get('location')).to.be.null; + }); + }); + + 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'); + expect(res.ok).to.be.false; + 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'); + expect(res.ok).to.be.false; + 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.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('code', 'ECONNRESET'); + }); + + it('should handle DNS-error response', function() { + url = 'http://domain.invalid'; + return expect(fetch(url)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('code', 'ENOTFOUND'); + }); + + it('should reject invalid json response', function() { + url = base + '/error/json'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('application/json'); + return expect(res.json()).to.eventually.be.rejectedWith(Error); + }); + }); + + it('should handle no content response', function() { + url = base + '/no-content'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(204); + expect(res.statusText).to.equal('No Content'); + expect(res.ok).to.be.true; + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.be.empty; + }); + }); + }); + + it('should throw on no-content json response', function() { + url = base + '/no-content'; + return fetch(url).then(function(res) { + return expect(res.json()).to.eventually.be.rejectedWith(FetchError); + }); + }); + + it('should handle no content response with gzip encoding', function() { + url = base + '/no-content/gzip'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(204); + expect(res.statusText).to.equal('No Content'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); + expect(res.ok).to.be.true; + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.be.empty; + }); + }); + }); + + it('should handle not modified response', function() { + url = base + '/not-modified'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(304); + expect(res.statusText).to.equal('Not Modified'); + expect(res.ok).to.be.false; + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.be.empty; + }); + }); + }); + + it('should handle not modified response with gzip encoding', function() { + url = base + '/not-modified/gzip'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(304); + expect(res.statusText).to.equal('Not Modified'); + expect(res.headers.get('content-encoding')).to.equal('gzip'); + expect(res.ok).to.be.false; + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.be.empty; + }); + }); + }); + + it('should decompress gzip response', function() { + url = base + '/gzip'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.equal('hello world'); + }); + }); + }); + + it('should decompress deflate response', function() { + url = base + '/deflate'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.equal('hello world'); + }); + }); + }); + + it('should decompress deflate raw response from old apache server', function() { + url = base + '/deflate-raw'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.equal('hello world'); + }); + }); + }); + + it('should skip decompression if unsupported', function() { + url = base + '/sdch'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.equal('fake sdch string'); + }); + }); + }); + + it('should reject if response compression is invalid', function() { + url = base + '/invalid-content-encoding'; + return fetch(url).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return expect(res.text()).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('code', 'Z_DATA_ERROR'); + }); + }); + + it('should allow disabling auto decompression', function() { + url = base + '/gzip'; + opts = { + compress: false + }; + return fetch(url, opts).then(function(res) { + expect(res.headers.get('content-type')).to.equal('text/plain'); + return res.text().then(function(result) { + expect(result).to.be.a('string'); + expect(result).to.not.equal('hello world'); + }); + }); + }); + + it('should allow custom timeout', function() { + this.timeout(500); + url = base + '/timeout'; + opts = { + timeout: 100 + }; + return expect(fetch(url, opts)).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'request-timeout'); + }); + + it('should allow custom timeout on response body', function() { + this.timeout(500); + url = base + '/slow'; + opts = { + timeout: 100 + }; + return fetch(url, opts).then(function(res) { + expect(res.ok).to.be.true; + return expect(res.text()).to.eventually.be.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'body-timeout'); + }); + }); + + it('should clear internal timeout on fetch response', function (done) { + this.timeout(1000); + spawn('node', ['-e', 'require("./")("' + base + '/hello", { timeout: 5000 })']) + .on('exit', function () { + done(); + }); + }); + + it('should clear internal timeout on fetch redirect', function (done) { + this.timeout(1000); + spawn('node', ['-e', 'require("./")("' + base + '/redirect/301", { timeout: 5000 })']) + .on('exit', function () { + done(); + }); + }); + + it('should clear internal timeout on fetch error', function (done) { + this.timeout(1000); + spawn('node', ['-e', 'require("./")("' + base + '/error/reset", { timeout: 5000 })']) + .on('exit', function () { + done(); + }); + }); + + it('should allow POST request', function() { + url = base + '/inspect'; + opts = { + method: 'POST' + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.headers['transfer-encoding']).to.be.undefined; + expect(res.headers['content-length']).to.equal('0'); + }); + }); + + it('should allow POST request with string body', function() { + url = base + '/inspect'; + opts = { + method: 'POST' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.body).to.equal('a=1'); + expect(res.headers['transfer-encoding']).to.be.undefined; + expect(res.headers['content-length']).to.equal('3'); + }); + }); + + it('should allow POST request with buffer body', function() { + url = base + '/inspect'; + opts = { + method: 'POST' + , body: new Buffer('a=1', 'utf-8') + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.body).to.equal('a=1'); + expect(res.headers['transfer-encoding']).to.equal('chunked'); + expect(res.headers['content-length']).to.be.undefined; + }); + }); + + it('should allow POST request with readable stream as body', function() { + var body = resumer().queue('a=1').end(); + body = body.pipe(new stream.PassThrough()); + + url = base + '/inspect'; + opts = { + method: 'POST' + , body: body + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.body).to.equal('a=1'); + expect(res.headers['transfer-encoding']).to.equal('chunked'); + expect(res.headers['content-length']).to.be.undefined; + }); + }); + + it('should allow POST request with form-data as body', function() { + var form = new FormData(); + form.append('a','1'); + + url = base + '/multipart'; + opts = { + method: 'POST' + , body: form + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.headers['content-type']).to.contain('multipart/form-data'); + expect(res.headers['content-length']).to.be.a('string'); + expect(res.body).to.equal('a=1'); + }); + }); + + it('should allow POST request with form-data using stream as body', function() { + var form = new FormData(); + form.append('my_field', fs.createReadStream('test/dummy.txt')); + + url = base + '/multipart'; + opts = { + method: 'POST' + , body: form + }; + + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.headers['content-type']).to.contain('multipart/form-data'); + expect(res.headers['content-length']).to.be.undefined; + expect(res.body).to.contain('my_field='); + }); + }); + + it('should allow POST request with form-data as body and custom headers', function() { + var form = new FormData(); + form.append('a','1'); + + var headers = form.getHeaders(); + headers['b'] = '2'; + + url = base + '/multipart'; + opts = { + method: 'POST' + , body: form + , headers: headers + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.headers['content-type']).to.contain('multipart/form-data'); + expect(res.headers['content-length']).to.be.a('string'); + expect(res.headers.b).to.equal('2'); + expect(res.body).to.equal('a=1'); + }); + }); + + it('should allow POST request with object body', function() { + url = base + '/inspect'; + // note that fetch simply calls tostring on an object + opts = { + method: 'POST' + , body: { a:1 } + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.body).to.equal('[object Object]'); + }); + }); + + 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 POST request with string body', function() { + url = base + '/inspect'; + opts = { + method: 'POST' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('POST'); + expect(res.body).to.equal('a=1'); + expect(res.headers['transfer-encoding']).to.be.undefined; + expect(res.headers['content-length']).to.equal('3'); + }); + }); + + it('should allow DELETE request with string body', function() { + url = base + '/inspect'; + opts = { + method: 'DELETE' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('DELETE'); + expect(res.body).to.equal('a=1'); + expect(res.headers['transfer-encoding']).to.be.undefined; + expect(res.headers['content-length']).to.equal('3'); + }); + }); + + it('should allow PATCH request', function() { + url = base + '/inspect'; + opts = { + method: 'PATCH' + , body: 'a=1' + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.method).to.equal('PATCH'); + expect(res.body).to.equal('a=1'); + }); + }); + + 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); + return res.text(); + }).then(function(text) { + expect(text).to.equal(''); + }); + }); + + it('should allow HEAD request with content-encoding header', function() { + url = base + '/error/404'; + opts = { + method: 'HEAD' + }; + return fetch(url, opts).then(function(res) { + expect(res.status).to.equal(404); + expect(res.headers.get('content-encoding')).to.equal('gzip'); + return res.text(); + }).then(function(text) { + expect(text).to.equal(''); + }); + }); + + it('should allow OPTIONS request', function() { + url = base + '/options'; + opts = { + method: 'OPTIONS' + }; + return fetch(url, opts).then(function(res) { + expect(res.status).to.equal(200); + expect(res.statusText).to.equal('OK'); + expect(res.headers.get('allow')).to.equal('GET, HEAD, OPTIONS'); + 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, multiple chunk', function() { + url = base + '/size/chunk'; + opts = { + size: 5 + }; + 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.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'max-size'); + }); + }); + + it('should support maximum response size, single chunk', function() { + url = base + '/size/long'; + opts = { + size: 5 + }; + 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.rejected + .and.be.an.instanceOf(FetchError) + .and.have.property('type', 'max-size'); + }); + }); + + it('should support encoding decode, xml dtd detect', function() { + url = base + '/encoding/euc-jp'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + return res.text().then(function(result) { + expect(result).to.equal('<?xml version="1.0" encoding="EUC-JP"?><title>日本語</title>'); + }); + }); + }); + + it('should support encoding decode, content-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 default to utf8 encoding', function() { + url = base + '/encoding/utf8'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + expect(res.headers.get('content-type')).to.be.null; + return res.text().then(function(result) { + expect(result).to.equal('中文'); + }); + }); + }); + + it('should support uncommon content-type order, charset in front', function() { + url = base + '/encoding/order1'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + return res.text().then(function(result) { + expect(result).to.equal('中文'); + }); + }); + }); + + it('should support uncommon content-type order, end with qs', function() { + url = base + '/encoding/order2'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + return res.text().then(function(result) { + expect(result).to.equal('中文'); + }); + }); + }); + + it('should support chunked encoding, html4 detect', function() { + url = base + '/encoding/chunked'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + // because node v0.12 doesn't have str.repeat + var padding = new Array(10 + 1).join('a'); + return res.text().then(function(result) { + expect(result).to.equal(padding + '<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" /><div>日本語</div>'); + }); + }); + }); + + it('should only do encoding detection up to 1024 bytes', function() { + url = base + '/encoding/invalid'; + return fetch(url).then(function(res) { + expect(res.status).to.equal(200); + // because node v0.12 doesn't have str.repeat + var padding = new Array(1200 + 1).join('a'); + return res.text().then(function(result) { + expect(result).to.not.equal(padding + '中文'); + }); + }); + }); + + it('should allow piping response body as stream', function(done) { + url = base + '/hello'; + fetch(url).then(function(res) { + expect(res.body).to.be.an.instanceof(stream.Transform); + res.body.on('data', function(chunk) { + if (chunk === null) { + return; + } + expect(chunk.toString()).to.equal('world'); + }); + res.body.on('end', function() { + done(); + }); + }); + }); + + it('should allow cloning a response, and use both as stream', function(done) { + url = base + '/hello'; + return fetch(url).then(function(res) { + var counter = 0; + var r1 = res.clone(); + expect(res.body).to.be.an.instanceof(stream.Transform); + expect(r1.body).to.be.an.instanceof(stream.Transform); + res.body.on('data', function(chunk) { + if (chunk === null) { + return; + } + expect(chunk.toString()).to.equal('world'); + }); + res.body.on('end', function() { + counter++; + if (counter == 2) { + done(); + } + }); + r1.body.on('data', function(chunk) { + if (chunk === null) { + return; + } + expect(chunk.toString()).to.equal('world'); + }); + r1.body.on('end', function() { + counter++; + if (counter == 2) { + done(); + } + }); + }); + }); + + it('should allow cloning a json response and log it as text response', function() { + url = base + '/json'; + return fetch(url).then(function(res) { + var r1 = res.clone(); + return fetch.Promise.all([res.json(), r1.text()]).then(function(results) { + expect(results[0]).to.deep.equal({name: 'value'}); + expect(results[1]).to.equal('{"name":"value"}'); + }); + }); + }); + + it('should allow cloning a json response, and then log it as text response', function() { + url = base + '/json'; + return fetch(url).then(function(res) { + var r1 = res.clone(); + return res.json().then(function(result) { + expect(result).to.deep.equal({name: 'value'}); + return r1.text().then(function(result) { + expect(result).to.equal('{"name":"value"}'); + }); + }); + }); + }); + + it('should allow cloning a json response, first log as text response, then return json object', function() { + url = base + '/json'; + return fetch(url).then(function(res) { + var r1 = res.clone(); + return r1.text().then(function(result) { + expect(result).to.equal('{"name":"value"}'); + return res.json().then(function(result) { + expect(result).to.deep.equal({name: 'value'}); + }); + }); + }); + }); + + it('should not allow cloning a response after its been used', function() { + url = base + '/hello'; + return fetch(url).then(function(res) { + return res.text().then(function(result) { + expect(function() { + var r1 = res.clone(); + }).to.throw(Error); + }); + }) + }); + + it('should allow get all responses of a header', function() { + url = base + '/cookie'; + return fetch(url).then(function(res) { + expect(res.headers.get('set-cookie')).to.equal('a=1'); + expect(res.headers.get('Set-Cookie')).to.equal('a=1'); + expect(res.headers.getAll('set-cookie')).to.deep.equal(['a=1', 'b=1']); + expect(res.headers.getAll('Set-Cookie')).to.deep.equal(['a=1', 'b=1']); + }); + }); + + it('should allow iterating through all headers', function() { + var headers = new Headers({ + a: 1 + , b: [2, 3] + , c: [4] + }); + expect(headers).to.have.property('forEach'); + + var result = []; + headers.forEach(function(val, key) { + result.push([key, val]); + }); + + expected = [ + ["a", "1"] + , ["b", "2"] + , ["b", "3"] + , ["c", "4"] + ]; + expect(result).to.deep.equal(expected); + }); + + 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 send request with connection keep-alive if agent is provided', function() { + url = base + '/inspect'; + opts = { + agent: new http.Agent({ + keepAlive: true + }) + }; + return fetch(url, opts).then(function(res) { + return res.json(); + }).then(function(res) { + expect(res.headers['connection']).to.equal('keep-alive'); + }); + }); + + it('should ignore unsupported attributes while reading headers', function() { + var FakeHeader = function() {}; + // prototypes are ignored + FakeHeader.prototype.z = 'fake'; + + var res = new FakeHeader; + // valid + res.a = 'string'; + res.b = ['1','2']; + res.c = ''; + res.d = []; + // common mistakes, normalized + res.e = 1; + res.f = [1, 2]; + // invalid, ignored + res.g = { a:1 }; + res.h = undefined; + res.i = null; + res.j = NaN; + res.k = true; + res.l = false; + res.m = new Buffer('test'); + + var h1 = new Headers(res); + + expect(h1._headers['a']).to.include('string'); + expect(h1._headers['b']).to.include('1'); + expect(h1._headers['b']).to.include('2'); + expect(h1._headers['c']).to.include(''); + expect(h1._headers['d']).to.be.undefined; + + expect(h1._headers['e']).to.include('1'); + expect(h1._headers['f']).to.include('1'); + expect(h1._headers['f']).to.include('2'); + + expect(h1._headers['g']).to.be.undefined; + expect(h1._headers['h']).to.be.undefined; + expect(h1._headers['i']).to.be.undefined; + expect(h1._headers['j']).to.be.undefined; + expect(h1._headers['k']).to.be.undefined; + expect(h1._headers['l']).to.be.undefined; + expect(h1._headers['m']).to.be.undefined; + + expect(h1._headers['z']).to.be.undefined; + }); + + it('should wrap headers', function() { + var h1 = new Headers({ + a: '1' + }); + + var h2 = new Headers(h1); + h2.set('b', '1'); + + var h3 = new Headers(h2); + h3.append('a', '2'); + + expect(h1._headers['a']).to.include('1'); + expect(h1._headers['a']).to.not.include('2'); + + expect(h2._headers['a']).to.include('1'); + expect(h2._headers['a']).to.not.include('2'); + expect(h2._headers['b']).to.include('1'); + + expect(h3._headers['a']).to.include('1'); + expect(h3._headers['a']).to.include('2'); + expect(h3._headers['b']).to.include('1'); + }); + + it('should support fetch with Request instance', function() { + url = base + '/hello'; + var req = new Request(url); + return fetch(req).then(function(res) { + expect(res.url).to.equal(url); + expect(res.ok).to.be.true; + expect(res.status).to.equal(200); + }); + }); + + it('should support wrapping Request instance', function() { + url = base + '/hello'; + + var form = new FormData(); + form.append('a', '1'); + + var r1 = new Request(url, { + method: 'POST' + , follow: 1 + , body: form + }); + var r2 = new Request(r1, { + follow: 2 + }); + + expect(r2.url).to.equal(url); + expect(r2.method).to.equal('POST'); + // note that we didn't clone the body + expect(r2.body).to.equal(form); + expect(r1.follow).to.equal(1); + expect(r2.follow).to.equal(2); + expect(r1.counter).to.equal(0); + expect(r2.counter).to.equal(0); + }); + + it('should support overwrite Request instance', function() { + url = base + '/inspect'; + var req = new Request(url, { + method: 'POST' + , headers: { + a: '1' + } + }); + return fetch(req, { + method: 'GET' + , headers: { + a: '2' + } + }).then(function(res) { + return res.json(); + }).then(function(body) { + expect(body.method).to.equal('GET'); + expect(body.headers.a).to.equal('2'); + }); + }); + + it('should support empty options in Response constructor', function() { + var body = resumer().queue('a=1').end(); + body = body.pipe(new stream.PassThrough()); + var res = new Response(body); + return res.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support parsing headers in Response constructor', function() { + var res = new Response(null, { + headers: { + a: '1' + } + }); + expect(res.headers.get('a')).to.equal('1'); + }); + + it('should support text() method in Response constructor', function() { + var res = new Response('a=1'); + return res.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support json() method in Response constructor', function() { + var res = new Response('{"a":1}'); + return res.json().then(function(result) { + expect(result.a).to.equal(1); + }); + }); + + it('should support buffer() method in Response constructor', function() { + var res = new Response('a=1'); + return res.buffer().then(function(result) { + expect(result.toString()).to.equal('a=1'); + }); + }); + + it('should support clone() method in Response constructor', function() { + var body = resumer().queue('a=1').end(); + body = body.pipe(new stream.PassThrough()); + var res = new Response(body, { + headers: { + a: '1' + } + , url: base + , status: 346 + , statusText: 'production' + }); + var cl = res.clone(); + expect(cl.headers.get('a')).to.equal('1'); + expect(cl.url).to.equal(base); + expect(cl.status).to.equal(346); + expect(cl.statusText).to.equal('production'); + expect(cl.ok).to.be.false; + // clone body shouldn't be the same body + expect(cl.body).to.not.equal(body); + return cl.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support stream as body in Response constructor', function() { + var body = resumer().queue('a=1').end(); + body = body.pipe(new stream.PassThrough()); + var res = new Response(body); + return res.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support string as body in Response constructor', function() { + var res = new Response('a=1'); + return res.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support buffer as body in Response constructor', function() { + var res = new Response(new Buffer('a=1')); + return res.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should default to 200 as status code', function() { + var res = new Response(null); + expect(res.status).to.equal(200); + }); + + it('should support parsing headers in Request constructor', function() { + url = base; + var req = new Request(url, { + headers: { + a: '1' + } + }); + expect(req.url).to.equal(url); + expect(req.headers.get('a')).to.equal('1'); + }); + + it('should support text() method in Request constructor', function() { + url = base; + var req = new Request(url, { + body: 'a=1' + }); + expect(req.url).to.equal(url); + return req.text().then(function(result) { + expect(result).to.equal('a=1'); + }); + }); + + it('should support json() method in Request constructor', function() { + url = base; + var req = new Request(url, { + body: '{"a":1}' + }); + expect(req.url).to.equal(url); + return req.json().then(function(result) { + expect(result.a).to.equal(1); + }); + }); + + it('should support buffer() method in Request constructor', function() { + url = base; + var req = new Request(url, { + body: 'a=1' + }); + expect(req.url).to.equal(url); + return req.buffer().then(function(result) { + expect(result.toString()).to.equal('a=1'); + }); + }); + + it('should support arbitrary url in Request constructor', function() { + url = 'anything'; + var req = new Request(url); + expect(req.url).to.equal('anything'); + }); + + it('should support clone() method in Request constructor', function() { + url = base; + var body = resumer().queue('a=1').end(); + body = body.pipe(new stream.PassThrough()); + var agent = new http.Agent(); + var req = new Request(url, { + body: body + , method: 'POST' + , redirect: 'manual' + , headers: { + b: '2' + } + , follow: 3 + , compress: false + , agent: agent + }); + var cl = req.clone(); + expect(cl.url).to.equal(url); + expect(cl.method).to.equal('POST'); + expect(cl.redirect).to.equal('manual'); + expect(cl.headers.get('b')).to.equal('2'); + expect(cl.follow).to.equal(3); + expect(cl.compress).to.equal(false); + expect(cl.method).to.equal('POST'); + expect(cl.counter).to.equal(0); + expect(cl.agent).to.equal(agent); + // clone body shouldn't be the same body + expect(cl.body).to.not.equal(body); + return fetch.Promise.all([cl.text(), req.text()]).then(function(results) { + expect(results[0]).to.equal('a=1'); + expect(results[1]).to.equal('a=1'); + }); + }); + + it('should support text(), json() and buffer() method in Body constructor', function() { + var body = new Body('a=1'); + expect(body).to.have.property('text'); + expect(body).to.have.property('json'); + expect(body).to.have.property('buffer'); + }); + + it('should create custom FetchError', function() { + var systemError = new Error('system'); + systemError.code = 'ESOMEERROR'; + + var err = new FetchError('test message', 'test-error', systemError); + expect(err).to.be.an.instanceof(Error); + expect(err).to.be.an.instanceof(FetchError); + expect(err.name).to.equal('FetchError'); + expect(err.message).to.equal('test message'); + expect(err.type).to.equal('test-error'); + expect(err.code).to.equal('ESOMEERROR'); + expect(err.errno).to.equal('ESOMEERROR'); + }); + + 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); + expect(res.ok).to.be.true; + }); + }); + +}); |