From ee610c6fc66bb46527265cd0d23eb6e0a457560d Mon Sep 17 00:00:00 2001 From: Jacob Gable Date: Sun, 26 May 2013 13:51:58 -0500 Subject: [PATCH] Error handlers --- core/shared/errorHandling.js | 59 +++++++++++++ core/test/ghost/dataProvider.json_spec.js | 2 +- core/test/ghost/errorHandling_spec.js | 103 ++++++++++++++++++++++ core/test/ghost/ghost_spec.js | 2 +- package.json | 3 +- 5 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 core/shared/errorHandling.js create mode 100644 core/test/ghost/errorHandling_spec.js diff --git a/core/shared/errorHandling.js b/core/shared/errorHandling.js new file mode 100644 index 0000000000..dc17de13e1 --- /dev/null +++ b/core/shared/errorHandling.js @@ -0,0 +1,59 @@ +(function() { + "use strict"; + + var _ = require('underscore'), + errors; + + /** + * Basic error handling helpers + */ + errors = { + throwError: function(err) { + if (!err) { + return; + } + + if (_.isString(err)) { + throw new Error(err); + } + + throw err; + }, + + logError: function (err) { + // TODO: Logging framework hookup + console.log("Error occurred: ", err.message || err); + }, + + logAndThrowError: function (err) { + this.logError(err); + + this.throwError(err); + }, + + logErrorWithMessage: function (msg) { + var self = this; + + return function () { + self.logError(msg); + }; + }, + + logErrorWithRedirect: function (msg, redirectTo, req, res) { + var self = this; + + return function () { + self.logError(msg); + + if (_.isFunction(res.redirect)) { + res.redirect(redirectTo); + } + }; + } + }; + + // Ensure our 'this' context in the functions + _.bindAll(errors, "throwError", "logError", "logAndThrowError", "logErrorWithMessage", "logErrorWithRedirect"); + + module.exports = errors; +}()); \ No newline at end of file diff --git a/core/test/ghost/dataProvider.json_spec.js b/core/test/ghost/dataProvider.json_spec.js index 88cec4f975..c264427f5f 100644 --- a/core/test/ghost/dataProvider.json_spec.js +++ b/core/test/ghost/dataProvider.json_spec.js @@ -8,7 +8,7 @@ describe("dataProvider.json", function () { - it("is a singleton", function() { + it("is a singleton", function () { var provider1 = new DataProvider(), provider2 = new DataProvider(); diff --git a/core/test/ghost/errorHandling_spec.js b/core/test/ghost/errorHandling_spec.js new file mode 100644 index 0000000000..7dedeb9c46 --- /dev/null +++ b/core/test/ghost/errorHandling_spec.js @@ -0,0 +1,103 @@ +/*globals describe, beforeEach, it*/ + +(function () { + "use strict"; + + var should = require('should'), + when = require('when'), + sinon = require('sinon'), + errors = require('../../shared/errorHandling'); + + describe("Error handling", function () { + + // Just getting rid of jslint unused error + should.exist(errors); + + it("throws error objects", function () { + var toThrow = new Error("test1"), + runThrowError = function () { + errors.throwError(toThrow); + }; + + runThrowError.should.throw("test1"); + }); + + it("throws error strings", function () { + var toThrow = "test2", + runThrowError = function () { + errors.throwError(toThrow); + }; + + runThrowError.should.throw("test2"); + }); + + it("logs errors", function () { + var err = new Error("test1"), + logStub = sinon.stub(console, "log"); + + errors.logError(err); + + // Calls log with message on Error objects + logStub.calledWith("Error occurred: ", err.message).should.equal(true); + + logStub.reset(); + + err = "test2"; + + errors.logError(err); + + // Calls log with string on strings + logStub.calledWith("Error occurred: ", err).should.equal(true); + + logStub.restore(); + }); + + it("logs promise errors with custom messages", function(done) { + var def = when.defer(), + prom = def.promise, + logStub = sinon.stub(console, "log"); + + prom.then(function () { + throw new Error("Ran success handler"); + }, errors.logErrorWithMessage("test1")); + + prom.otherwise(function () { + logStub.calledWith("Error occurred: ", "test1").should.equal(true); + logStub.restore(); + + done(); + }); + + def.reject(); + }); + + it("logs promise errors and redirects", function(done) { + var def = when.defer(), + prom = def.promise, + req = null, + res = { + redirect: function() { + return; + } + }, + logStub = sinon.stub(console, "log"), + redirectStub = sinon.stub(res, "redirect"); + + prom.then(function () { + throw new Error("Ran success handler"); + }, errors.logErrorWithRedirect("test1", "/testurl", req, res)); + + prom.otherwise(function () { + logStub.calledWith("Error occurred: ", "test1").should.equal(true); + logStub.restore(); + + redirectStub.calledWith('/testurl').should.equal(true); + redirectStub.restore(); + + done(); + }); + + def.reject(); + }); + }); +}()); \ No newline at end of file diff --git a/core/test/ghost/ghost_spec.js b/core/test/ghost/ghost_spec.js index 78440c7f28..e037df61af 100644 --- a/core/test/ghost/ghost_spec.js +++ b/core/test/ghost/ghost_spec.js @@ -8,7 +8,7 @@ describe("Ghost API", function () { - it("is a singleton", function() { + it("is a singleton", function () { var ghost1 = new Ghost(), ghost2 = new Ghost(); diff --git a/package.json b/package.json index cc15aa7174..ecd589610f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "should": "~1.2.2", "grunt-mocha-test": "~0.4.0", "grunt-shell": "~0.2.2", - "grunt-contrib-sass": "~0.3.0" + "grunt-contrib-sass": "~0.3.0", + "sinon": "~1.7.2" } }