Repository: node-nock/nock
Pull request #864 (2017-03-22 10:15:49)

[#863] Fix matchBody for object and array comparison

coveralls: 
[![Coverage Status](https://coveralls.io/builds/10715996/badge)](https://coveralls.io/builds/10715996)

Coverage increased (+0.02%) to 92.686% when pulling **6961c4fa875cc580721f89ebe0e0903ae2876517 on fasterize:fix_match_body** into **934f1c39013a2a60dfa4999e78540cae2d819259 on node-nock:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/10715996/badge)](https://coveralls.io/builds/10715996)

Coverage increased (+0.02%) to 92.686% when pulling **6961c4fa875cc580721f89ebe0e0903ae2876517 on fasterize:fix_match_body** into **934f1c39013a2a60dfa4999e78540cae2d819259 on node-nock:master**.


Patch:
diff --git a/lib/intercept.js b/lib/intercept.js
index 34699b7..a2ca20e 100644
--- a/lib/intercept.js
+++ b/lib/intercept.js
@@ -123,11 +123,6 @@ function remove(interceptor) {
 }
 
 function removeAll() {
-  Object.keys(allInterceptors).forEach(function(key) {
-    allInterceptors[key].scopes.forEach(function(interceptor) {
-      interceptor.scope.keyedInterceptors = {};
-    });
-  });
   allInterceptors = {};
 }
 
diff --git a/lib/match_body.js b/lib/match_body.js
index 83784f0..953720b 100644
--- a/lib/match_body.js
+++ b/lib/match_body.js
@@ -29,7 +29,7 @@ function matchBody(spec, body) {
     return body.match(spec);
   }
 
-  if (!isMultipart && typeof spec === "string") {
+  if (typeof spec === "string") {
     spec = spec.replace(/\r?\n|\r/g, '');
   }
 
@@ -59,6 +59,11 @@ function deepEqualExtended(spec, body) {
   }
   if (spec && (spec.constructor === Object || spec.constructor === Array) && body) {
     var keys = Object.keys(spec);
+    var actualKeys = Object.keys(body);
+    if (actualKeys.length !== keys.length) {
+      return false;
+    }
+
     for (var i = 0; i < keys.length; i++) {
       if (!deepEqualExtended(spec[keys[i]], body[keys[i]])) {
         return false;
diff --git a/package.json b/package.json
index 50a7df5..bd071fe 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
     "testing",
     "isolation"
   ],
-  "version": "9.0.11",
+  "version": "9.0.9",
   "author": "Pedro Teixeira <pedro.teixeira@gmail.com>",
   "contributors": [
     {


Test patch:
diff --git a/tests/test_body_match.js b/tests/test_body_match.js
index fb645cb..4799fd7 100644
--- a/tests/test_body_match.js
+++ b/tests/test_body_match.js
@@ -5,83 +5,55 @@ var test = require('tap').test;
 var mikealRequest = require('request');
 var assert = require('assert');
 
-test('match body with regex', function (t) {
-
+var testBodyMatch = function (expected, actual, shouldMatch, t) {
   nock('http://encodingsareus.com')
-    .post('/', {auth: {passwd: /a.+/}})
+    .post('/', expected)
     .reply(200);
 
   mikealRequest({
     url: 'http://encodingsareus.com/',
     method: 'post',
-    json: {
-      auth: {
-        passwd: 'abc'
-      }
-    },
+    json: actual,
   }, function(err, res) {
-    if (err) throw err;
-    assert.equal(res.statusCode, 200);
-    t.end();
+    shouldMatch
+      ? assert.equal(res.statusCode, 200)
+      : assert(err && /No match for request/.test(err.message), 'nock should not intercept the request');
+      t.end();
   });
+}
 
-});
-
-test('match body with regex inside array', function (t) {
 
-  nock('http://encodingsareus.com')
-    .post('/', {items: [{name: /t.+/}]})
-    .reply(200);
+test('body matching', function (t) {
+  t.test('match body with regex', function (t2) {
+    testBodyMatch({auth: {passwd: /a.+/}}, {auth: {passwd: 'abc'}}, true, t2);
+  });
 
-  mikealRequest({
-    url: 'http://encodingsareus.com/',
-    method: 'post',
-    json: {
-      items: [{
-        name: 'test'
-      }]
-    },
-  }, function(err, res) {
-    if (err) throw err;
-    assert.equal(res.statusCode, 200);
-    t.end();
+  t.test('match body with regex inside array', function (t2) {
+    testBodyMatch({items: [{name: /t.+/}]}, {items: [{name: 'test'}]}, true, t2);
   });
-})
 
-test('match body with empty object inside', function (t) {
+  t.test('failing body matching with regex inside array', function (t2) {
+    testBodyMatch({items: [{name: /o.+/}]}, {items: [{name: 'test'}]}, false, t2);
+  });
 
-  nock('http://encodingsareus.com')
-    .post('/', { obj: {}})
-    .reply(200);
+  t.test('failing body matching with different array length', function (t2) {
+    testBodyMatch({items: [1, 2]}, {items: [{items: [1, 2, 3]}]}, false, t2);
+  });
 
-  mikealRequest({
-    url: 'http://encodingsareus.com/',
-    method: 'post',
-    json: {
-      obj: {}
-    },
-  }, function(err, res) {
-    if (err) throw err;
-    assert.equal(res.statusCode, 200);
-    t.end();
+  t.test('match body with empty object inside', function (t2) {
+    testBodyMatch({ obj: {}}, {obj: {}}, true, t2);
   });
-})
 
-test('match body with form multipart', function(t) {
+  t.test('match body with identical objects', function (t2) {
+    testBodyMatch({ obj: {b:1, a:1}}, {obj: {b:1, a:1}}, true, t2);
+  });
 
-  nock('http://encodingsareus.com')
-    .post('/', "--fixboundary\r\nContent-Disposition: form-data; name=\"field\"\r\n\r\nvalue\r\n--fixboundary--\r\n")
-    .reply(200);
+  t.test('failing body matching with different objects', function (t2) {
+    testBodyMatch({ obj: {a:1}}, {obj: {b:1, a:1}}, false, t2);
+  });
 
-  var r = mikealRequest({
-    url: 'http://encodingsareus.com/',
-    method: 'post',
-  }, function(err, res) {
-    if (err) throw err;
-    assert.equal(res.statusCode, 200);
-    t.end();
+  t.test('failing body matching with different nested objects', function (t2) {
+    testBodyMatch({ obj: {a: {b:1}}}, {obj: {a: {b:1, c:1}}}, false, t2);
   });
-  var form = r.form();
-  form._boundary = 'fixboundary';  // fix boundary so that request could match at all
-  form.append('field', 'value');
+  t.end();
 });
diff --git a/tests/test_common.js b/tests/test_common.js
index a16295d..822b0d1 100644
--- a/tests/test_common.js
+++ b/tests/test_common.js
@@ -30,7 +30,9 @@ tap.test('matchBody should not ignore new line characters from strings when Cont
       'Content-Type': "multipart/form-data;"
     }
   }
-  var matched = matchBody.call(testThis, str1, str2);
+  var matched = matchBody.call(testThis, function (body) {
+    return body === str1;
+  }, str2);
   t.true(matched);
   t.end()
 });
@@ -43,7 +45,9 @@ tap.test('matchBody should not ignore new line characters from strings when Cont
       'Content-Type': ["multipart/form-data;"]
     }
   }
-  var matched = matchBody.call(testThis, str1, str2);
+  var matched = matchBody.call(testThis, function (body) {
+    return body === str1;
+  }, str2);
   t.true(matched);
   t.end()
 });
diff --git a/tests/test_intercept.js b/tests/test_intercept.js
index 7d1f1c4..0feb9bd 100755
--- a/tests/test_intercept.js
+++ b/tests/test_intercept.js
@@ -2249,23 +2249,6 @@ test('clean all works', function(t) {
 
 });
 
-test('cleanAll should remove pending mocks from all scopes', function(t) {
-  var scope1 = nock('http://example.org')
-    .get('/somepath')
-    .reply(200, 'hey');
-  t.deepEqual(scope1.pendingMocks(), ['GET http://example.org:80/somepath']);
-  var scope2 = nock('http://example.com')
-    .get('/somepath')
-    .reply(200, 'hey');
-  t.deepEqual(scope2.pendingMocks(), ['GET http://example.com:80/somepath']);
-
-  nock.cleanAll();
-
-  t.deepEqual(scope1.pendingMocks(), []);
-  t.deepEqual(scope2.pendingMocks(), []);
-  t.end();
-});
-
 test('is done works', function(t) {
   var scope = nock('http://amazon.com')
     .get('/nonexistent')