Repository: node-nock/nock (js)

Issue:
Nock does not respect callback parameters on req.write and req.end
Node's [req.write](https://nodejs.org/api/http.html#http_request_write_chunk_encoding_callback) and [req.end](https://nodejs.org/api/http.html#http_request_end_data_encoding_callback) accept callback parameters, but Nock does not. This is the cause of #1044 / olalonde/follow-redirects#77 / axios/axios#1271.

Fix in #1047.
  

Pull request description:
Implement callback on req.write and req.end
The Node.js write and end methods take a callback as third argument; this pull request also adds them to the Nock interface.

Fixes #1046 and #1044.

Patch:
diff --git a/lib/request_overrider.js b/lib/request_overrider.js
index e8eb82c..7ce8d95 100644
--- a/lib/request_overrider.js
+++ b/lib/request_overrider.js
@@ -127,15 +127,20 @@ function RequestOverrider(req, options, interceptors, remove, cb) {
 
   req.socket = response.socket = Socket({ proto: options.proto });
 
-  req.write = function(buffer, encoding) {
+  req.write = function(buffer, encoding, callback) {
     debug('write', arguments);
-    if (buffer && !aborted) {
-      if (! Buffer.isBuffer(buffer)) {
-        buffer = new Buffer(buffer, encoding);
+    if (!aborted) {
+      if (buffer) {
+        if (!Buffer.isBuffer(buffer)) {
+          buffer = new Buffer(buffer, encoding);
+        }
+        requestBodyBuffers.push(buffer);
+      }
+      if (typeof callback === 'function') {
+        callback();
       }
-      requestBodyBuffers.push(buffer);
     }
-    if (aborted) {
+    else {
       emitError(new Error('Request aborted'));
     }
 
@@ -146,13 +151,17 @@ function RequestOverrider(req, options, interceptors, remove, cb) {
     return false;
   };
 
-  req.end = function(buffer, encoding) {
+  req.end = function(buffer, encoding, callback) {
     debug('req.end');
     if (!aborted && !ended) {
-      req.write(buffer, encoding);
-      end(cb);
-      req.emit('finish');
-      req.emit('end');
+      req.write(buffer, encoding, function () {
+        if (typeof callback === 'function') {
+          callback();
+        }
+        end(cb);
+        req.emit('finish');
+        req.emit('end');
+      });
     }
     if (aborted) {
       emitError(new Error('Request aborted'));


Test patch:
diff --git a/tests/test_intercept.js b/tests/test_intercept.js
index 5e05790..dea4874 100644
--- a/tests/test_intercept.js
+++ b/tests/test_intercept.js
@@ -3297,6 +3297,65 @@ test('delay works with replyWithError', function (t) {
 
 });
 
+test("write callback called", function(t) {
+  var scope = nock('http://www.filterboddiezregexp.com')
+    .filteringRequestBody(/mia/, 'nostra')
+    .post('/', 'mamma nostra')
+    .reply(200, "Hello World!");
+
+  var callbackCalled = false;
+  var req = http.request({
+                           host: "www.filterboddiezregexp.com"
+                           , method: 'POST'
+                           , path: '/'
+                           , port: 80
+                         }, function(res) {
+    t.equal(callbackCalled, true);
+    t.equal(res.statusCode, 200);
+    res.on('end', function() {
+      scope.done();
+      t.end();
+    });
+    // Streams start in 'paused' mode and must be started.
+    // See https://nodejs.org/api/stream.html#stream_class_stream_readable
+    res.resume();
+  });
+
+  req.write('mamma mia', null, function() {
+    callbackCalled = true;
+    req.end();
+  });
+});
+
+test("end callback called", function(t) {
+  var scope = nock('http://www.filterboddiezregexp.com')
+    .filteringRequestBody(/mia/, 'nostra')
+    .post('/', 'mamma nostra')
+    .reply(200, "Hello World!");
+
+  var callbackCalled = false;
+  var req = http.request({
+                           host: "www.filterboddiezregexp.com"
+                           , method: 'POST'
+                           , path: '/'
+                           , port: 80
+                         }, function(res) {
+    t.equal(callbackCalled, true);
+    t.equal(res.statusCode, 200);
+    res.on('end', function() {
+      scope.done();
+      t.end();
+    });
+    // Streams start in 'paused' mode and must be started.
+    // See https://nodejs.org/api/stream.html#stream_class_stream_readable
+    res.resume();
+  });
+
+  req.end('mamma mia', null, function() {
+    callbackCalled = true;
+  });
+});
+
 test("finish event fired before end event (bug-139)", function(t) {
   var scope = nock('http://www.filterboddiezregexp.com')
     .filteringRequestBody(/mia/, 'nostra')