UNPKG

unexpected

Version:
211 lines (182 loc) 6.33 kB
var utils = require('./utils'); var errorMethodBlacklist = ['message', 'line', 'sourceId', 'sourceURL', 'stack', 'stackArray'].reduce(function (result, prop) { result[prop] = true; return result; }, {}); function UnexpectedError(expect, assertion, parent) { this.errorMode = (assertion && assertion.errorMode) || 'default'; var base = Error.call(this, ''); if (Error.captureStackTrace) { Error.captureStackTrace(this, UnexpectedError); } else { // Throw the error to make sure it has its stack serialized: try { throw base; } catch (err) {} this.stack = base.stack; } this.expect = expect; this.assertion = assertion || null; this.parent = parent || null; this.name = 'UnexpectedError'; } UnexpectedError.prototype = Object.create(Error.prototype); UnexpectedError.prototype._isUnexpected = true; UnexpectedError.prototype.isUnexpected = true; UnexpectedError.prototype.buildDiff = function () { var expect = this.expect; return this.createDiff && this.createDiff(expect.output.clone(), function (actual, expected) { return expect.diff(actual, expected); }, function (v, depth) { return expect.inspect(v, depth || Infinity); }, function (actual, expected) { return expect.equal(actual, expected); }); }; UnexpectedError.prototype.getDefaultErrorMessage = function (options) { var message = this.expect.output.clone(); if (this.assertion) { message.append(this.assertion.standardErrorMessage(options)); } else { message.append(this.output); } var errorWithDiff = this; while (!errorWithDiff.createDiff && errorWithDiff.parent) { errorWithDiff = errorWithDiff.parent; } if (errorWithDiff && errorWithDiff.createDiff) { var comparison = errorWithDiff.buildDiff(); if (comparison) { message.nl(2).append(comparison.diff); } } return message; }; UnexpectedError.prototype.getNestedErrorMessage = function (options) { var message = this.expect.output.clone(); if (this.assertion) { message.append(this.assertion.standardErrorMessage(options)); } else { message.append(this.output); } var parent = this.parent; while (parent.getErrorMode() === 'bubble') { parent = parent.parent; } message.nl() .indentLines() .i().block(parent.getErrorMessage(utils.extend({}, options || {}, { compact: this.assertion && parent.assertion && this.assertion.subject === parent.assertion.subject }))); return message; }; UnexpectedError.prototype.getDiffMethod = function () { var errorWithDiff = this; while (!errorWithDiff.createDiff && errorWithDiff.parent) { errorWithDiff = errorWithDiff.parent; } return errorWithDiff && errorWithDiff.createDiff || null; }; UnexpectedError.prototype.getDiff = function () { var errorWithDiff = this; while (!errorWithDiff.createDiff && errorWithDiff.parent) { errorWithDiff = errorWithDiff.parent; } if (errorWithDiff) { var diffResult = errorWithDiff.buildDiff(); if (diffResult && diffResult.diff) { return diffResult; } else { return null; } } else { return null; } }; UnexpectedError.prototype.getDiffMessage = function () { var message = this.expect.output.clone(); var comparison = this.getDiff(); if (comparison) { message.append(comparison.diff); } else if (this.assertion) { message.append(this.assertion.standardErrorMessage()); } else { message.append(this.output); } return message; }; UnexpectedError.prototype.getErrorMode = function () { if (!this.parent) { switch (this.errorMode) { case 'default': case 'bubbleThrough': return this.errorMode; default: return 'default'; } } else { return this.errorMode; } }; UnexpectedError.prototype.getErrorMessage = function (options) { // Search for any parent error that has mode bubble through on the // error these should be bubbled to the top var errorWithBubbleThough = this.parent; while (errorWithBubbleThough && errorWithBubbleThough.getErrorMode() !== 'bubbleThrough') { errorWithBubbleThough = errorWithBubbleThough.parent; } if (errorWithBubbleThough) { return errorWithBubbleThough.getErrorMessage(); } var errorMode = this.getErrorMode(); switch (errorMode) { case 'nested': return this.getNestedErrorMessage(options); case 'default': return this.getDefaultErrorMessage(options); case 'bubbleThrough': return this.getDefaultErrorMessage(); case 'bubble': return this.parent.getErrorMessage(options); case 'diff': return this.getDiffMessage(); default: throw new Error("Unknown error mode: '" + errorMode + "'"); } }; UnexpectedError.prototype.serializeMessage = function (outputFormat) { if (!this._hasSerializedErrorMessage) { var message = this.getErrorMessage(); if (outputFormat === 'html') { outputFormat = 'text'; this.htmlMessage = message.toString('html'); } this.message = '\n' + message.toString(outputFormat); this._hasSerializedErrorMessage = true; } }; UnexpectedError.prototype.clone = function () { var that = this; var newError = new UnexpectedError(this.expect); Object.keys(that).forEach(function (key) { if (!errorMethodBlacklist[key]) { newError[key] = that[key]; } }); return newError; }; UnexpectedError.prototype.getLabel = function () { var currentError = this; while (currentError && !currentError.label) { currentError = currentError.parent; } return (currentError && currentError.label) || null; }; UnexpectedError.prototype.getParents = function () { var result = []; var parent = this.parent; while (parent) { result.push(parent); parent = parent.parent; } return result; }; UnexpectedError.prototype.getAllErrors = function () { var result = this.getParents(); result.unshift(this); return result; }; module.exports = UnexpectedError;