Spaces:
Paused
Paused
| ; | |
| /** | |
| * @module Base | |
| */ | |
| /** | |
| * Module dependencies. | |
| */ | |
| var diff = require('diff'); | |
| var milliseconds = require('ms'); | |
| var utils = require('../utils'); | |
| var supportsColor = require('supports-color'); | |
| var constants = require('../runner').constants; | |
| var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; | |
| var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; | |
| const isBrowser = utils.isBrowser(); | |
| function getBrowserWindowSize() { | |
| if ('innerHeight' in global) { | |
| return [global.innerHeight, global.innerWidth]; | |
| } | |
| // In a Web Worker, the DOM Window is not available. | |
| return [640, 480]; | |
| } | |
| /** | |
| * Expose `Base`. | |
| */ | |
| exports = module.exports = Base; | |
| /** | |
| * Check if both stdio streams are associated with a tty. | |
| */ | |
| var isatty = isBrowser || (process.stdout.isTTY && process.stderr.isTTY); | |
| /** | |
| * Save log references to avoid tests interfering (see GH-3604). | |
| */ | |
| var consoleLog = console.log; | |
| /** | |
| * Enable coloring by default, except in the browser interface. | |
| */ | |
| exports.useColors = | |
| !isBrowser && | |
| (supportsColor.stdout || process.env.MOCHA_COLORS !== undefined); | |
| /** | |
| * Inline diffs instead of +/- | |
| */ | |
| exports.inlineDiffs = false; | |
| /** | |
| * Default color map. | |
| */ | |
| exports.colors = { | |
| pass: 90, | |
| fail: 31, | |
| 'bright pass': 92, | |
| 'bright fail': 91, | |
| 'bright yellow': 93, | |
| pending: 36, | |
| suite: 0, | |
| 'error title': 0, | |
| 'error message': 31, | |
| 'error stack': 90, | |
| checkmark: 32, | |
| fast: 90, | |
| medium: 33, | |
| slow: 31, | |
| green: 32, | |
| light: 90, | |
| 'diff gutter': 90, | |
| 'diff added': 32, | |
| 'diff removed': 31, | |
| 'diff added inline': '30;42', | |
| 'diff removed inline': '30;41' | |
| }; | |
| /** | |
| * Default symbol map. | |
| */ | |
| exports.symbols = { | |
| ok: 'β', | |
| err: 'β', | |
| dot: 'β€', | |
| comma: ',', | |
| bang: '!' | |
| }; | |
| // With node.js on Windows: use symbols available in terminal default fonts | |
| if (process.platform === 'win32') { | |
| exports.symbols.ok = '\u221A'; | |
| exports.symbols.err = '\u00D7'; | |
| exports.symbols.dot = '.'; | |
| } | |
| /** | |
| * Color `str` with the given `type`, | |
| * allowing colors to be disabled, | |
| * as well as user-defined color | |
| * schemes. | |
| * | |
| * @private | |
| * @param {string} type | |
| * @param {string} str | |
| * @return {string} | |
| */ | |
| var color = (exports.color = function(type, str) { | |
| if (!exports.useColors) { | |
| return String(str); | |
| } | |
| return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; | |
| }); | |
| /** | |
| * Expose term window size, with some defaults for when stderr is not a tty. | |
| */ | |
| exports.window = { | |
| width: 75 | |
| }; | |
| if (isatty) { | |
| if (isBrowser) { | |
| exports.window.width = getBrowserWindowSize()[1]; | |
| } else { | |
| exports.window.width = process.stdout.getWindowSize(1)[0]; | |
| } | |
| } | |
| /** | |
| * Expose some basic cursor interactions that are common among reporters. | |
| */ | |
| exports.cursor = { | |
| hide: function() { | |
| isatty && process.stdout.write('\u001b[?25l'); | |
| }, | |
| show: function() { | |
| isatty && process.stdout.write('\u001b[?25h'); | |
| }, | |
| deleteLine: function() { | |
| isatty && process.stdout.write('\u001b[2K'); | |
| }, | |
| beginningOfLine: function() { | |
| isatty && process.stdout.write('\u001b[0G'); | |
| }, | |
| CR: function() { | |
| if (isatty) { | |
| exports.cursor.deleteLine(); | |
| exports.cursor.beginningOfLine(); | |
| } else { | |
| process.stdout.write('\r'); | |
| } | |
| } | |
| }; | |
| var showDiff = (exports.showDiff = function(err) { | |
| return ( | |
| err && | |
| err.showDiff !== false && | |
| sameType(err.actual, err.expected) && | |
| err.expected !== undefined | |
| ); | |
| }); | |
| function stringifyDiffObjs(err) { | |
| if (!utils.isString(err.actual) || !utils.isString(err.expected)) { | |
| err.actual = utils.stringify(err.actual); | |
| err.expected = utils.stringify(err.expected); | |
| } | |
| } | |
| /** | |
| * Returns a diff between 2 strings with coloured ANSI output. | |
| * | |
| * @description | |
| * The diff will be either inline or unified dependent on the value | |
| * of `Base.inlineDiff`. | |
| * | |
| * @param {string} actual | |
| * @param {string} expected | |
| * @return {string} Diff | |
| */ | |
| var generateDiff = (exports.generateDiff = function(actual, expected) { | |
| try { | |
| return exports.inlineDiffs | |
| ? inlineDiff(actual, expected) | |
| : unifiedDiff(actual, expected); | |
| } catch (err) { | |
| var msg = | |
| '\n ' + | |
| color('diff added', '+ expected') + | |
| ' ' + | |
| color('diff removed', '- actual: failed to generate Mocha diff') + | |
| '\n'; | |
| return msg; | |
| } | |
| }); | |
| /** | |
| * Outputs the given `failures` as a list. | |
| * | |
| * @public | |
| * @memberof Mocha.reporters.Base | |
| * @variation 1 | |
| * @param {Object[]} failures - Each is Test instance with corresponding | |
| * Error property | |
| */ | |
| exports.list = function(failures) { | |
| var multipleErr, multipleTest; | |
| Base.consoleLog(); | |
| failures.forEach(function(test, i) { | |
| // format | |
| var fmt = | |
| color('error title', ' %s) %s:\n') + | |
| color('error message', ' %s') + | |
| color('error stack', '\n%s\n'); | |
| // msg | |
| var msg; | |
| var err; | |
| if (test.err && test.err.multiple) { | |
| if (multipleTest !== test) { | |
| multipleTest = test; | |
| multipleErr = [test.err].concat(test.err.multiple); | |
| } | |
| err = multipleErr.shift(); | |
| } else { | |
| err = test.err; | |
| } | |
| var message; | |
| if (err.message && typeof err.message.toString === 'function') { | |
| message = err.message + ''; | |
| } else if (typeof err.inspect === 'function') { | |
| message = err.inspect() + ''; | |
| } else { | |
| message = ''; | |
| } | |
| var stack = err.stack || message; | |
| var index = message ? stack.indexOf(message) : -1; | |
| if (index === -1) { | |
| msg = message; | |
| } else { | |
| index += message.length; | |
| msg = stack.slice(0, index); | |
| // remove msg from stack | |
| stack = stack.slice(index + 1); | |
| } | |
| // uncaught | |
| if (err.uncaught) { | |
| msg = 'Uncaught ' + msg; | |
| } | |
| // explicitly show diff | |
| if (!exports.hideDiff && showDiff(err)) { | |
| stringifyDiffObjs(err); | |
| fmt = | |
| color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); | |
| var match = message.match(/^([^:]+): expected/); | |
| msg = '\n ' + color('error message', match ? match[1] : msg); | |
| msg += generateDiff(err.actual, err.expected); | |
| } | |
| // indent stack trace | |
| stack = stack.replace(/^/gm, ' '); | |
| // indented test title | |
| var testTitle = ''; | |
| test.titlePath().forEach(function(str, index) { | |
| if (index !== 0) { | |
| testTitle += '\n '; | |
| } | |
| for (var i = 0; i < index; i++) { | |
| testTitle += ' '; | |
| } | |
| testTitle += str; | |
| }); | |
| Base.consoleLog(fmt, i + 1, testTitle, msg, stack); | |
| }); | |
| }; | |
| /** | |
| * Constructs a new `Base` reporter instance. | |
| * | |
| * @description | |
| * All other reporters generally inherit from this reporter. | |
| * | |
| * @public | |
| * @class | |
| * @memberof Mocha.reporters | |
| * @param {Runner} runner - Instance triggers reporter actions. | |
| * @param {Object} [options] - runner options | |
| */ | |
| function Base(runner, options) { | |
| var failures = (this.failures = []); | |
| if (!runner) { | |
| throw new TypeError('Missing runner argument'); | |
| } | |
| this.options = options || {}; | |
| this.runner = runner; | |
| this.stats = runner.stats; // assigned so Reporters keep a closer reference | |
| runner.on(EVENT_TEST_PASS, function(test) { | |
| if (test.duration > test.slow()) { | |
| test.speed = 'slow'; | |
| } else if (test.duration > test.slow() / 2) { | |
| test.speed = 'medium'; | |
| } else { | |
| test.speed = 'fast'; | |
| } | |
| }); | |
| runner.on(EVENT_TEST_FAIL, function(test, err) { | |
| if (showDiff(err)) { | |
| stringifyDiffObjs(err); | |
| } | |
| // more than one error per test | |
| if (test.err && err instanceof Error) { | |
| test.err.multiple = (test.err.multiple || []).concat(err); | |
| } else { | |
| test.err = err; | |
| } | |
| failures.push(test); | |
| }); | |
| } | |
| /** | |
| * Outputs common epilogue used by many of the bundled reporters. | |
| * | |
| * @public | |
| * @memberof Mocha.reporters | |
| */ | |
| Base.prototype.epilogue = function() { | |
| var stats = this.stats; | |
| var fmt; | |
| Base.consoleLog(); | |
| // passes | |
| fmt = | |
| color('bright pass', ' ') + | |
| color('green', ' %d passing') + | |
| color('light', ' (%s)'); | |
| Base.consoleLog(fmt, stats.passes || 0, milliseconds(stats.duration)); | |
| // pending | |
| if (stats.pending) { | |
| fmt = color('pending', ' ') + color('pending', ' %d pending'); | |
| Base.consoleLog(fmt, stats.pending); | |
| } | |
| // failures | |
| if (stats.failures) { | |
| fmt = color('fail', ' %d failing'); | |
| Base.consoleLog(fmt, stats.failures); | |
| Base.list(this.failures); | |
| Base.consoleLog(); | |
| } | |
| Base.consoleLog(); | |
| }; | |
| /** | |
| * Pads the given `str` to `len`. | |
| * | |
| * @private | |
| * @param {string} str | |
| * @param {string} len | |
| * @return {string} | |
| */ | |
| function pad(str, len) { | |
| str = String(str); | |
| return Array(len - str.length + 1).join(' ') + str; | |
| } | |
| /** | |
| * Returns inline diff between 2 strings with coloured ANSI output. | |
| * | |
| * @private | |
| * @param {String} actual | |
| * @param {String} expected | |
| * @return {string} Diff | |
| */ | |
| function inlineDiff(actual, expected) { | |
| var msg = errorDiff(actual, expected); | |
| // linenos | |
| var lines = msg.split('\n'); | |
| if (lines.length > 4) { | |
| var width = String(lines.length).length; | |
| msg = lines | |
| .map(function(str, i) { | |
| return pad(++i, width) + ' |' + ' ' + str; | |
| }) | |
| .join('\n'); | |
| } | |
| // legend | |
| msg = | |
| '\n' + | |
| color('diff removed inline', 'actual') + | |
| ' ' + | |
| color('diff added inline', 'expected') + | |
| '\n\n' + | |
| msg + | |
| '\n'; | |
| // indent | |
| msg = msg.replace(/^/gm, ' '); | |
| return msg; | |
| } | |
| /** | |
| * Returns unified diff between two strings with coloured ANSI output. | |
| * | |
| * @private | |
| * @param {String} actual | |
| * @param {String} expected | |
| * @return {string} The diff. | |
| */ | |
| function unifiedDiff(actual, expected) { | |
| var indent = ' '; | |
| function cleanUp(line) { | |
| if (line[0] === '+') { | |
| return indent + colorLines('diff added', line); | |
| } | |
| if (line[0] === '-') { | |
| return indent + colorLines('diff removed', line); | |
| } | |
| if (line.match(/@@/)) { | |
| return '--'; | |
| } | |
| if (line.match(/\\ No newline/)) { | |
| return null; | |
| } | |
| return indent + line; | |
| } | |
| function notBlank(line) { | |
| return typeof line !== 'undefined' && line !== null; | |
| } | |
| var msg = diff.createPatch('string', actual, expected); | |
| var lines = msg.split('\n').splice(5); | |
| return ( | |
| '\n ' + | |
| colorLines('diff added', '+ expected') + | |
| ' ' + | |
| colorLines('diff removed', '- actual') + | |
| '\n\n' + | |
| lines | |
| .map(cleanUp) | |
| .filter(notBlank) | |
| .join('\n') | |
| ); | |
| } | |
| /** | |
| * Returns character diff for `err`. | |
| * | |
| * @private | |
| * @param {String} actual | |
| * @param {String} expected | |
| * @return {string} the diff | |
| */ | |
| function errorDiff(actual, expected) { | |
| return diff | |
| .diffWordsWithSpace(actual, expected) | |
| .map(function(str) { | |
| if (str.added) { | |
| return colorLines('diff added inline', str.value); | |
| } | |
| if (str.removed) { | |
| return colorLines('diff removed inline', str.value); | |
| } | |
| return str.value; | |
| }) | |
| .join(''); | |
| } | |
| /** | |
| * Colors lines for `str`, using the color `name`. | |
| * | |
| * @private | |
| * @param {string} name | |
| * @param {string} str | |
| * @return {string} | |
| */ | |
| function colorLines(name, str) { | |
| return str | |
| .split('\n') | |
| .map(function(str) { | |
| return color(name, str); | |
| }) | |
| .join('\n'); | |
| } | |
| /** | |
| * Object#toString reference. | |
| */ | |
| var objToString = Object.prototype.toString; | |
| /** | |
| * Checks that a / b have the same type. | |
| * | |
| * @private | |
| * @param {Object} a | |
| * @param {Object} b | |
| * @return {boolean} | |
| */ | |
| function sameType(a, b) { | |
| return objToString.call(a) === objToString.call(b); | |
| } | |
| Base.consoleLog = consoleLog; | |
| Base.abstract = true; | |