diff options
| author | Yuchen Pei <hi@ypei.me> | 2022-07-28 15:32:10 +1000 | 
|---|---|---|
| committer | Yuchen Pei <hi@ypei.me> | 2022-07-28 15:32:10 +1000 | 
| commit | 5b10a10743b8459f64fe83e0ff420f69da79c9a4 (patch) | |
| tree | c61904d688247790181d4955a4074b8c94302c03 /utilities/hash_script/node_modules/node-fetch/test | |
| parent | b98cb70b1bcd5b211aaa5d2675f96416911c0647 (diff) | |
Moving scripts and utilities into a new utilities dir
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; +		}); +	}); + +}); | 
