diff --git a/.gitignore b/.gitignore index c2658d7..b064cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +__testfile diff --git a/context.js b/context.js index 93972c5..f59595b 100644 --- a/context.js +++ b/context.js @@ -49,8 +49,13 @@ Namespace.prototype.run = function (fn) { return context; } catch (exception) { - if (exception) { - exception[ERROR_SYMBOL] = context; + if (exception && !exception[ERROR_SYMBOL]) { + Object.defineProperty(exception, ERROR_SYMBOL, { + configurable: true, + enumerable: false, + writable: false, + value: context + }); } throw exception; } @@ -76,8 +81,13 @@ Namespace.prototype.bind = function (fn, context) { return fn.apply(this, arguments); } catch (exception) { - if (exception) { - exception[ERROR_SYMBOL] = context; + if (exception && !exception[ERROR_SYMBOL]) { + Object.defineProperty(exception, ERROR_SYMBOL, { + configurable: true, + enumerable: false, + writable: false, + value: context + }); } throw exception; } diff --git a/test/error-handling.tap.js b/test/error-handling.tap.js index f792dbb..fafc501 100644 --- a/test/error-handling.tap.js +++ b/test/error-handling.tap.js @@ -114,7 +114,7 @@ test("throw in process.nextTick attaches the context", function (t) { test("throw in setTimeout attaches the context", function (t) { t.plan(3); - var namespace = cls.createNamespace('cls@nexttick'); + var namespace = cls.createNamespace('cls@settimeout'); var d = domain.create(); d.on('error', function (e) { @@ -122,7 +122,7 @@ test("throw in setTimeout attaches the context", function (t) { t.equal(namespace.fromException(e)['value'], 'transaction set', "found the inner value"); - cls.destroyNamespace('cls@nexttick'); + cls.destroyNamespace('cls@settimeout'); }); namespace.run(function () { @@ -132,10 +132,36 @@ test("throw in setTimeout attaches the context", function (t) { setTimeout(d.bind(function () { namespace.run(function () { namespace.set('value', 'transaction set'); - throw new Error("cls@nexttick explosion"); + throw new Error("cls@settimeout explosion"); }); })); t.equal(namespace.get('value'), 'transaction clear', "everything was reset"); }); }); + +test("errors can be serialized", function (t) { + var namespace = cls.createNamespace('cls@serialized'); + namespace.run(function () { + var d = domain.create(); + + d.on('error', function (blerg) { + var canSerialize = true; + try { + JSON.stringify(blerg); + } catch (e) { + canSerialize = false; + } + t.ok(canSerialize, "errors serialize safely"); + cls.destroyNamespace('cls@serialized'); + t.end(); + }); + + // tap is only trying to help + process.nextTick(d.bind(function () { + namespace.run(function () { + throw new Error("explicitly nonlocal exit"); + }); + })); + }); +});