diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e4d8168..3008768f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ Please update the docs accordingly so that there are no discrepencies between th ### Developing -- `grunt test` run the jasmine and nodeunit tests +- `grunt test` run the jasmine and mocha tests - `grunt build` run webpack and bundle the source - `grunt version` prepare the code for release - `grunt watch:test` watch for changes and run `test` diff --git a/Gruntfile.js b/Gruntfile.js index c4a92c3d..3f527456 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -65,8 +65,13 @@ module.exports = function(grunt) { } }, - nodeunit: { - all: ['test/unit/**/*.js'] + mochaTest: { + test: { + src: ['test/unit/**/*.js'] + }, + options: { + timeout: 30000, + }, }, watch: { @@ -96,7 +101,7 @@ module.exports = function(grunt) { grunt.file.write('bower.json', JSON.stringify(bower, null, 2)); }); - grunt.registerTask('test', 'Run the jasmine and nodeunit tests', ['eslint', 'nodeunit', 'karma:single', 'ts']); + grunt.registerTask('test', 'Run the jasmine and mocha tests', ['eslint', 'mochaTest', 'karma:single', 'ts']); grunt.registerTask('build', 'Run webpack and bundle the source', ['clean', 'webpack']); grunt.registerTask('version', 'Sync version info for a release', ['usebanner', 'package2bower']); }; diff --git a/package.json b/package.json index e788f32c..dbd88543 100644 --- a/package.json +++ b/package.json @@ -39,10 +39,10 @@ "grunt-banner": "^0.6.0", "grunt-cli": "^1.2.0", "grunt-contrib-clean": "^1.1.0", - "grunt-contrib-nodeunit": "^1.0.0", "grunt-contrib-watch": "^1.0.0", "grunt-eslint": "^20.1.0", "grunt-karma": "^2.0.0", + "grunt-mocha-test": "^0.13.3", "grunt-ts": "^6.0.0-beta.19", "grunt-webpack": "^1.0.18", "istanbul-instrumenter-loader": "^1.0.0", @@ -61,11 +61,12 @@ "karma-webpack": "^1.7.0", "load-grunt-tasks": "^3.5.2", "minimist": "^1.2.0", + "mocha": "^5.2.0", "sinon": "^4.5.0", - "webpack": "^1.13.1", - "webpack-dev-server": "^1.14.1", + "typescript": "^2.8.1", "url-search-params": "^0.10.0", - "typescript": "^2.8.1" + "webpack": "^1.13.1", + "webpack-dev-server": "^1.14.1" }, "browser": { "./lib/adapters/http.js": "./lib/adapters/xhr.js" diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index f88246cb..0dc4c6eb 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -3,26 +3,28 @@ var http = require('http'); var net = require('net'); var url = require('url'); var zlib = require('zlib'); +var assert = require('assert'); var fs = require('fs'); var server, proxy; -module.exports = { - tearDown: function (callback) { - server.close(); - server = null; +describe('supports http with nodejs', function () { + + afterEach(function () { + if (server) { + server.close(); + server = null; + } if (proxy) { proxy.close() proxy = null; } - if (process.env.http_proxy) { delete process.env.http_proxy; } + }); - callback(); - }, + it('should respect the timeout property', function (done) { - testTimeout: function (test) { server = http.createServer(function (req, res) { setTimeout(function () { res.end(); @@ -41,16 +43,16 @@ module.exports = { }); setTimeout(function () { - test.equal(success, false, 'request should not succeed'); - test.equal(failure, true, 'request should fail'); - test.equal(error.code, 'ECONNABORTED'); - test.equal(error.message, 'timeout of 250ms exceeded'); - test.done(); + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.code, 'ECONNABORTED'); + assert.equal(error.message, 'timeout of 250ms exceeded'); + done(); }, 300); }); - }, + }); - testJSON: function (test) { + it('should allow passing JSON', function (done) { var data = { firstName: 'Fred', lastName: 'Flintstone', @@ -62,13 +64,13 @@ module.exports = { res.end(JSON.stringify(data)); }).listen(4444, function () { axios.get('http://localhost:4444/').then(function (res) { - test.deepEqual(res.data, data); - test.done(); + assert.deepEqual(res.data, data); + done(); }); }); - }, + }); - testRedirect: function (test) { + it('should redirect', function (done) { var str = 'test response'; server = http.createServer(function (req, res) { @@ -83,14 +85,14 @@ module.exports = { } }).listen(4444, function () { axios.get('http://localhost:4444/one').then(function (res) { - test.equal(res.data, str); - test.equal(res.request.path, '/two'); - test.done(); + assert.equal(res.data, str); + assert.equal(res.request.path, '/two'); + done(); }); }); - }, + }); - testNoRedirect: function (test) { + it('should not redirect', function (done) { server = http.createServer(function (req, res) { res.setHeader('Location', '/foo'); res.statusCode = 302; @@ -102,14 +104,14 @@ module.exports = { return true; } }).then(function (res) { - test.equal(res.status, 302); - test.equal(res.headers['location'], '/foo'); - test.done(); + assert.equal(res.status, 302); + assert.equal(res.headers['location'], '/foo'); + done(); }); }); - }, + }); - testMaxRedirects: function (test) { + it('should support max redirects', function (done) { var i = 1; server = http.createServer(function (req, res) { res.setHeader('Location', '/' + i); @@ -120,19 +122,19 @@ module.exports = { axios.get('http://localhost:4444/', { maxRedirects: 3 }).catch(function (error) { - test.done(); + done(); }); }); - }, + }); - testTransparentGunzip: function (test) { + it('should support transparent gunzip', function (done) { var data = { firstName: 'Fred', lastName: 'Flintstone', emailAddr: 'fred@example.com' }; - zlib.gzip(JSON.stringify(data), function(err, zipped) { + zlib.gzip(JSON.stringify(data), function (err, zipped) { server = http.createServer(function (req, res) { res.setHeader('Content-Type', 'application/json;charset=utf-8'); @@ -140,27 +142,27 @@ module.exports = { res.end(zipped); }).listen(4444, function () { axios.get('http://localhost:4444/').then(function (res) { - test.deepEqual(res.data, data); - test.done(); + assert.deepEqual(res.data, data); + done(); }); }); }); - }, + }); - testGunzipErrorHandling: function (test) { + it('should support gunzip error handling', function (done) { server = http.createServer(function (req, res) { res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Content-Encoding', 'gzip'); res.end('invalid response'); }).listen(4444, function () { axios.get('http://localhost:4444/').catch(function (error) { - test.done(); + done(); }); }); - }, + }); - testUTF8: function (test) { + it('should support UTF8', function (done) { var str = Array(100000).join('ж'); server = http.createServer(function (req, res) { @@ -168,13 +170,13 @@ module.exports = { res.end(str); }).listen(4444, function () { axios.get('http://localhost:4444/').then(function (res) { - test.equal(res.data, str); - test.done(); + assert.equal(res.data, str); + done(); }); }); - }, + }); - testBasicAuth: function (test) { + it('should support basic auth', function (done) { server = http.createServer(function (req, res) { res.end(req.headers.authorization); }).listen(4444, function () { @@ -182,13 +184,13 @@ module.exports = { var headers = { Authorization: 'Bearer 1234' }; axios.get('http://' + user + '@localhost:4444/', { headers: headers }).then(function (res) { var base64 = Buffer.from(user + ':', 'utf8').toString('base64'); - test.equal(res.data, 'Basic ' + base64); - test.done(); + assert.equal(res.data, 'Basic ' + base64); + done(); }); }); - }, + }); - testBasicAuthWithHeader: function (test) { + it('should support basic auth with a header', function (done) { server = http.createServer(function (req, res) { res.end(req.headers.authorization); }).listen(4444, function () { @@ -196,13 +198,13 @@ module.exports = { var headers = { Authorization: 'Bearer 1234' }; axios.get('http://localhost:4444/', { auth: auth, headers: headers }).then(function (res) { var base64 = Buffer.from('foo:bar', 'utf8').toString('base64'); - test.equal(res.data, 'Basic ' + base64); - test.done(); + assert.equal(res.data, 'Basic ' + base64); + done(); }); }); - }, + }); - testMaxContentLength: function(test) { + it('should support max content length', function (done) { var str = Array(100000).join('ж'); server = http.createServer(function (req, res) { @@ -221,102 +223,101 @@ module.exports = { }); setTimeout(function () { - test.equal(success, false, 'request should not succeed'); - test.equal(failure, true, 'request should fail'); - test.equal(error.message, 'maxContentLength size of 2000 exceeded'); - test.done(); + assert.equal(success, false, 'request should not succeed'); + assert.equal(failure, true, 'request should fail'); + assert.equal(error.message, 'maxContentLength size of 2000 exceeded'); + done(); }, 100); }); - }, + }); - testSocket: function (test) { + it.skip('should support sockets', function (done) { server = net.createServer(function (socket) { - socket.on('data', function() { + socket.on('data', function () { socket.end('HTTP/1.1 200 OK\r\n\r\n'); }); - }).listen('./test.sock', function() { + }).listen('./test.sock', function () { axios({ socketPath: './test.sock', url: '/' }) - .then(function(resp) { - test.equal(resp.status, 200); - test.equal(resp.statusText, 'OK'); - test.done(); - }) - .catch(function (error) { - test.ifError(error); - test.done(); - }); + .then(function (resp) { + assert.equal(resp.status, 200); + assert.equal(resp.statusText, 'OK'); + done(); + }) + .catch(function (error) { + assert.ifError(error); + done(); + }); }); - }, + }); - testStream: function(test) { + it('should support streams', function (done) { server = http.createServer(function (req, res) { req.pipe(res); }).listen(4444, function () { axios.post('http://localhost:4444/', fs.createReadStream(__filename), { - responseType: 'stream' - }).then(function (res) { - var stream = res.data; - var string = ''; - stream.on('data', function (chunk) { - string += chunk.toString('utf8'); + responseType: 'stream' + }).then(function (res) { + var stream = res.data; + var string = ''; + stream.on('data', function (chunk) { + string += chunk.toString('utf8'); + }); + stream.on('end', function () { + assert.equal(string, fs.readFileSync(__filename, 'utf8')); + done(); + }); }); - stream.on('end', function () { - test.equal(string, fs.readFileSync(__filename, 'utf8')); - test.done(); - }); - }); }); - }, + }); - testFailedStream: function(test) { + it('should pass errors for a failed stream', function (done) { server = http.createServer(function (req, res) { req.pipe(res); }).listen(4444, function () { axios.post('http://localhost:4444/', fs.createReadStream('/does/not/exist') ).then(function (res) { - test.fail(); + assert.fail(); }).catch(function (err) { - test.equal(err.message, 'ENOENT: no such file or directory, open \'/does/not/exist\''); - test.done(); + assert.equal(err.message, 'ENOENT: no such file or directory, open \'/does/not/exist\''); + done(); }); }); - }, + }); - testBuffer: function(test) { - var buf = Buffer.from(1024); // Unsafe buffer < Buffer.poolSize (8192 bytes) - buf.fill('x'); + it('should support buffers', function (done) { + var buf = Buffer.alloc(1024, 'x'); // Unsafe buffer < Buffer.poolSize (8192 bytes) server = http.createServer(function (req, res) { - test.equal(req.headers['content-length'], buf.length.toString()); + assert.equal(req.headers['content-length'], buf.length.toString()); req.pipe(res); }).listen(4444, function () { axios.post('http://localhost:4444/', buf, { - responseType: 'stream' - }).then(function (res) { - var stream = res.data; - var string = ''; - stream.on('data', function (chunk) { - string += chunk.toString('utf8'); + responseType: 'stream' + }).then(function (res) { + var stream = res.data; + var string = ''; + stream.on('data', function (chunk) { + string += chunk.toString('utf8'); + }); + stream.on('end', function () { + assert.equal(string, buf.toString()); + done(); + }); }); - stream.on('end', function () { - test.equal(string, buf.toString()); - test.done(); - }); - }); }); - }, + }); - testHTTPProxy: function(test) { - server = http.createServer(function(req, res) { + it('should support HTTP proxies', function (done) { + server = http.createServer(function (req, res) { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); res.end('12345'); - }).listen(4444, function() { - proxy = http.createServer(function(request, response) { + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { var parsed = url.parse(request.url); var opts = { host: parsed.hostname, @@ -324,54 +325,54 @@ module.exports = { path: parsed.path }; - http.get(opts, function(res) { + http.get(opts, function (res) { var body = ''; - res.on('data', function(data) { + res.on('data', function (data) { body += data; }); - res.on('end', function() { + res.on('end', function () { response.setHeader('Content-Type', 'text/html; charset=UTF-8'); response.end(body + '6789'); }); }); - }).listen(4000, function() { + }).listen(4000, function () { axios.get('http://localhost:4444/', { proxy: { host: 'localhost', port: 4000 } - }).then(function(res) { - test.equal(res.data, '123456789', 'should pass through proxy'); - test.done(); + }).then(function (res) { + assert.equal(res.data, '123456789', 'should pass through proxy'); + done(); }); }); }); - }, + }); - testHTTPProxyDisabled: function(test) { + it('should not pass through disabled proxy', function (done) { // set the env variable process.env.http_proxy = 'http://does-not-exists.example.com:4242/'; - server = http.createServer(function(req, res) { + server = http.createServer(function (req, res) { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); res.end('123456789'); - }).listen(4444, function() { + }).listen(4444, function () { axios.get('http://localhost:4444/', { - proxy: false - }).then(function(res) { - test.equal(res.data, '123456789', 'should not pass through proxy'); - test.done(); - }); + proxy: false + }).then(function (res) { + assert.equal(res.data, '123456789', 'should not pass through proxy'); + done(); + }); }); - }, + }); - testHTTPProxyEnv: function(test) { - server = http.createServer(function(req, res) { + it('should support proxy set via env var', function (done) { + server = http.createServer(function (req, res) { res.setHeader('Content-Type', 'text/html; charset=UTF-8'); res.end('4567'); - }).listen(4444, function() { - proxy = http.createServer(function(request, response) { + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { var parsed = url.parse(request.url); var opts = { host: parsed.hostname, @@ -379,34 +380,34 @@ module.exports = { path: parsed.path }; - http.get(opts, function(res) { + http.get(opts, function (res) { var body = ''; - res.on('data', function(data) { + res.on('data', function (data) { body += data; }); - res.on('end', function() { + res.on('end', function () { response.setHeader('Content-Type', 'text/html; charset=UTF-8'); response.end(body + '1234'); }); }); - }).listen(4000, function() { + }).listen(4000, function () { // set the env variable process.env.http_proxy = 'http://localhost:4000/'; - axios.get('http://localhost:4444/').then(function(res) { - test.equal(res.data, '45671234', 'should use proxy set by process.env.http_proxy'); - test.done(); + axios.get('http://localhost:4444/').then(function (res) { + assert.equal(res.data, '45671234', 'should use proxy set by process.env.http_proxy'); + done(); }); }); }); - }, + }); - testHTTPProxyAuth: function(test) { - server = http.createServer(function(req, res) { + it('should support HTTP proxy auth', function (done) { + server = http.createServer(function (req, res) { res.end(); - }).listen(4444, function() { - proxy = http.createServer(function(request, response) { + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { var parsed = url.parse(request.url); var opts = { host: parsed.hostname, @@ -415,18 +416,18 @@ module.exports = { }; var proxyAuth = request.headers['proxy-authorization']; - http.get(opts, function(res) { + http.get(opts, function (res) { var body = ''; - res.on('data', function(data) { + res.on('data', function (data) { body += data; }); - res.on('end', function() { + res.on('end', function () { response.setHeader('Content-Type', 'text/html; charset=UTF-8'); response.end(proxyAuth); }); }); - }).listen(4000, function() { + }).listen(4000, function () { axios.get('http://localhost:4444/', { proxy: { host: 'localhost', @@ -436,20 +437,20 @@ module.exports = { password: 'pass' } } - }).then(function(res) { + }).then(function (res) { var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); - test.done(); + assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + done(); }); }); }); - }, + }); - testHTTPProxyAuthFromEnv: function(test) { - server = http.createServer(function(req, res) { + it('should support proxy auth from env', function (done) { + server = http.createServer(function (req, res) { res.end(); - }).listen(4444, function() { - proxy = http.createServer(function(request, response) { + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { var parsed = url.parse(request.url); var opts = { host: parsed.hostname, @@ -458,34 +459,34 @@ module.exports = { }; var proxyAuth = request.headers['proxy-authorization']; - http.get(opts, function(res) { + http.get(opts, function (res) { var body = ''; - res.on('data', function(data) { + res.on('data', function (data) { body += data; }); - res.on('end', function() { + res.on('end', function () { response.setHeader('Content-Type', 'text/html; charset=UTF-8'); response.end(proxyAuth); }); }); - }).listen(4000, function() { + }).listen(4000, function () { process.env.http_proxy = 'http://user:pass@localhost:4000/'; - axios.get('http://localhost:4444/').then(function(res) { + axios.get('http://localhost:4444/').then(function (res) { var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy set by process.env.http_proxy'); - test.done(); + assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy set by process.env.http_proxy'); + done(); }); }); }); - }, + }); - testHTTPProxyAuthWithHeader: function (test) { - server = http.createServer(function(req, res) { + it('should support proxy auth with header', function (done) { + server = http.createServer(function (req, res) { res.end(); - }).listen(4444, function() { - proxy = http.createServer(function(request, response) { + }).listen(4444, function () { + proxy = http.createServer(function (request, response) { var parsed = url.parse(request.url); var opts = { host: parsed.hostname, @@ -494,18 +495,18 @@ module.exports = { }; var proxyAuth = request.headers['proxy-authorization']; - http.get(opts, function(res) { + http.get(opts, function (res) { var body = ''; - res.on('data', function(data) { + res.on('data', function (data) { body += data; }); - res.on('end', function() { + res.on('end', function () { response.setHeader('Content-Type', 'text/html; charset=UTF-8'); response.end(proxyAuth); }); }); - }).listen(4000, function() { + }).listen(4000, function () { axios.get('http://localhost:4444/', { proxy: { host: 'localhost', @@ -518,28 +519,30 @@ module.exports = { headers: { 'Proxy-Authorization': 'Basic abc123' } - }).then(function(res) { + }).then(function (res) { var base64 = Buffer.from('user:pass', 'utf8').toString('base64'); - test.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); - test.done(); + assert.equal(res.data, 'Basic ' + base64, 'should authenticate to the proxy'); + done(); }); }); }); - }, + }); - testCancel: function(test) { + it('should support cancel', function (done) { var source = axios.CancelToken.source(); server = http.createServer(function (req, res) { // call cancel() when the request has been sent, but a response has not been received source.cancel('Operation has been canceled.'); - }).listen(4444, function() { + }).listen(4444, function () { axios.get('http://localhost:4444/', { cancelToken: source.token }).catch(function (thrown) { - test.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a Cancel obejct'); - test.equal(thrown.message, 'Operation has been canceled.'); - test.done(); + assert.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a Cancel obejct'); + assert.equal(thrown.message, 'Operation has been canceled.'); + done(); }); }); - } -}; + }); +}); + +