Merge "Copy all error properties in fromNativeValue."
diff --git a/src/proxy/websocket.js b/src/proxy/websocket.js
index 9deb710..b2d33f9 100644
--- a/src/proxy/websocket.js
+++ b/src/proxy/websocket.js
@@ -7,12 +7,13 @@
  * @fileoverview WebSocket client implementation
  */
 
-var WebSocket = require('ws');
-var Deferred = require('./../lib/deferred');
-var vlog = require('./../lib/vlog');
-var Proxy = require('./index');
 var isBrowser = require('is-browser');
+var WebSocket = require('ws');
+
 var byteUtil = require('../vdl/byte-util');
+var Deferred = require('./../lib/deferred');
+var Proxy = require('./index');
+var vlog = require('./../lib/vlog');
 var vom = require('../vom');
 
 /**
@@ -75,13 +76,11 @@
     // TODO(jasoncampbell): there can be more errors than just failed
     // connection, additionally there can be more than one error emitted. We
     // should take care to cover these cases.
-    // TODO(nlacasse): Add tests that check for this error when bad wspr url is
-    // provided.
-    var error = new Error('Failed to connect to wspr at url ' + self.url +
-        ': ' + e.message);
+    e.message = 'Failed to connect to wspr at url ' + self.url +
+        ': ' + e.message;
 
-    vlog.logger.error(error);
-    deferred.reject(error);
+    vlog.logger.error(e);
+    deferred.reject(e);
   };
 
   websocket.onmessage = function(frame) {
diff --git a/src/vdl/error-conversion.js b/src/vdl/error-conversion.js
index c788178..1f30af6 100644
--- a/src/vdl/error-conversion.js
+++ b/src/vdl/error-conversion.js
@@ -143,7 +143,18 @@
   var errID = err.id || unknown.id;
   var errRetryCode = err.retryCode || unknown.retryCode;
 
+  var errProps = {};
   if (err instanceof Error) {
+    Object.getOwnPropertyNames(err).forEach(function(propName) {
+      if (propName === 'message') {
+        // Skip 'message' field since we set that ourselves to be enumerable.
+        return;
+      }
+      errProps[propName] = Object.getOwnPropertyDescriptor(err, propName);
+      // Set the property to non-enumerable.
+      errProps[propName].enumerable = false;
+    });
+
     message = err.message;
 
     paramList = ['app', 'call', message];
@@ -169,12 +180,17 @@
   var EConstructor = errorMap[errID] || verror.UnknownError;
   var e = new EConstructor(args);
 
-  // Fill the remaining error parameters. By using new on an Error, we will have
-  // a stack trace. Add the correct id, retryCode, message, etc.
+  // Add properties from original error.
+  Object.defineProperties(e, errProps);
+
+  // Add verror fields.
   e.id = errID;
   e.retryCode = errRetryCode;
   e.resetArgs.apply(e, paramList);
+
+  // Add message and msg so that they will be enumerable.
   e.message = message;
   e.msg = message;
+
   return e;
 }
diff --git a/test/integration/test-client-bind-to.js b/test/integration/test-client-bind-to.js
index 53eb28c..bda032f 100644
--- a/test/integration/test-client-bind-to.js
+++ b/test/integration/test-client-bind-to.js
@@ -97,7 +97,9 @@
   vanadium.init({ wspr: 'http://bad-address.tld' }, onruntime);
 
   function onruntime(err, runtime) {
-    assert.ok(err instanceof Error);
+    assert.ok(err instanceof Error, 'returns an error');
+    assert.ok(err.message.indexOf('Failed to connect') >= 0,
+              'error is connection error');
     assert.end();
   }
 });
@@ -114,7 +116,9 @@
     assert.error('should not have succeeded');
     assert.end();
   }, function(err) {
-    assert.ok(err instanceof Error);
+    assert.ok(err instanceof Error, 'returns an error');
+    assert.ok(err.message.indexOf('Failed to connect') >= 0,
+              'error is connection error');
     assert.end();
   });
 });
diff --git a/test/vdl/test-vdl-errors.js b/test/vdl/test-vdl-errors.js
index b242931..156520a 100644
--- a/test/vdl/test-vdl-errors.js
+++ b/test/vdl/test-vdl-errors.js
@@ -61,16 +61,73 @@
   });
 }
 
-var unknownError = (new verror.UnknownError(null));
 test('var struct = ec.fromNativeValue(err)', function(assert) {
   var err = new Error(message);
-  var struct = ec.fromNativeValue(err, 'app', 'call');
-  struct.paramList = deepUnwrapParamList(struct.paramList);
+
+  // Add properties that NodeJS errors commonly have.
+  Object.defineProperties(err, {
+    arguments: {
+      value: undefined,
+      writable: true,
+      enumerable: false,
+      configurable: true
+    },
+    type: {
+      value: undefined,
+      writable: true,
+      enumerable: false,
+      configurable: true
+    },
+    errno: {
+      value: 34,
+      writable: true,
+      enumerable: true,
+      configurable: true
+    },
+    code: {
+      value: 'ENOENT',
+      writable: true,
+      enumerable: true,
+      configurable: true
+    },
+    path: {
+      value: '',
+      writable: true,
+      enumerable: true,
+      configurable: true
+    }
+  });
+
+  var verr = ec.fromNativeValue(err, 'app', 'call');
+  verr.paramList = deepUnwrapParamList(verr.paramList);
+
+  // Check that verr has the correct enumerable properties.
   var expectedError = new verror.UnknownError(null);
-  expectedError.message = message;
-  expectedError.msg = message;
-  expectedError.paramList = ['app', 'call', message];
-  assert.deepEqual(struct, expectedError);
+  expectedError.message = err.message;
+  expectedError.msg = err.message;
+  expectedError.paramList = ['app', 'call', err.message];
+  assert.deepEqual(verr, expectedError);
+
+  // Check that verr has the same properties (including non-enumerable
+  // properties) as the native error.
+  Object.getOwnPropertyNames(err).forEach(function(propName) {
+    assert.ok(verr.hasOwnProperty(propName), 'verror has expected property');
+    if (propName !== 'stack') {
+      // err.stack is a getter that returns different strings based on the
+      // error value, so we cannot check equality.
+      assert.equals(verr[propName], err[propName],
+                    'property matches original error');
+    }
+  });
+
+  // Check that 'code' and 'errno' properties are preserved from original
+  // error, and are not enumerable.
+  (['code', 'errno']).forEach(function(prop) {
+    assert.equal(verr[prop], err[prop], 'has the correct value for ' + prop );
+    assert.equal(Object.getOwnPropertyDescriptor(verr, 'code').enumerable,
+                 false, 'property ' + prop + ' is not enumerable');
+  });
+
   assert.end();
 });
 
@@ -99,6 +156,7 @@
 });
 
 test('Error => Struct => Error', function(assert) {
+  var unknownError = new verror.UnknownError(null);
   var message = 'testing JS error conversion';
   var original = new Error(message);
   var struct = ec.fromNativeValue(original);