tunnckoCore/dush-tap-report

View on GitHub
index.js

Summary

Maintainability
C
1 day
Test Coverage
/*!
 * dush-tap-report <https://github.com/tunnckoCore/dush-tap-report>
 *
 * Copyright (c) Charlike Mike Reagent <@tunnckoCore> (https://i.am.charlike.online)
 * Released under the MIT license.
 */

'use strict'

var util = require('util')
var extend = require('extend-shallow')
var stackdata = require('stacktrace-metadata')

/**
 * > A simple TAP report producing plugin for [dush][] or anything based on it.
 * It returns a function that can be passed to dush's `.use` method. This plugin
 * will also work for [minibase][] and [base][] mini frameworks for building robust apps.
 *
 * **Example**
 *
 * ```js
 * const reporter = require('dush-tap-report')
 * const dush = require('dush')
 *
 * const app = dush()
 *
 * // provide a fake stats object
 * // so `finish` to work correctly
 * app.use(reporter({
 *   stats: {
 *     count: 3,
 *     pass: 2,
 *     fail: 1
 *   }
 * }))
 *
 * const item = {
 *   index: 1,
 *   title: 'some passing test'
 * }
 * const failing = {
 *   index: 2,
 *   title: 'failing test, sorry',
 *   reason: new Error('some sad error here')
 * }
 * const item2 = {
 *   index: 3,
 *   title: 'awesome test is okey'
 * }
 *
 * app.emit('start', app)
 * // => 'TAP version 13'
 *
 * app.emit('pass', app, item)
 * // =>
 * // # :) some passing test
 * // ok 1 - some passing test
 *
 * app.emit('fail', app, failing)
 * // =>
 * // # :( failing test, sorry
 * // not ok 2 - failing test, sorry
 *
 * app.emit('pass', app, item2)
 * // =>
 * // # :) awesome test is okey
 * // ok 3 - awesome test is okey
 *
 * app.emit('finish', app)
 * // =>
 * // 1..3
 * // # tests 3
 * // # pass  2
 * // # fail  1
 * ```
 *
 * @param  {Object} `options` optional options, merged with `app.options`,
 *                            passed to [stacktrace-metadata][] and [find-callsite][]
 * @param  {Function} `options.writeLine` a logger function called on each line, default `console.log`
 * @param  {Boolean} `options.cleanStack` if `false` won't clean stack trace from node internals,
 *                                        [clean-stacktrace][]
 * @param  {Boolean} `options.shortStack` if `false` full stack traces, otherwise they are just four
 * @param  {Boolean} `options.showStack` if `false` the error.stack will be empty string
 * @param  {Boolean} `options.relativePaths` if `false` paths in stack traces will be absolute,
 *                                           [clean-stacktrace-relative-paths][]
 * @param  {Function} `options.mapper` called on each line of the stack with `(line, index)` signature
 * @param  {String} `options.cwd` current working directory, default `process.cwd()`
 * @return {Function} a plugin function that should be
 *                    passed to `.use` method of [minibase][], [base][] or [dush][]
 * @api public
 */

module.exports = function tapReport (options) {
  return function tapReport_ (app) {
    app.options = extend({
      writeLine: console.log
    }, app.options, options)

    var log = app.options.writeLine

    app.once('start', function start (app) {
      log('TAP version 13')
    })

    app.on('pass', function onPass (app, test) {
      log('# :)', test.title)
      log('ok', test.index, '-', test.title)
    })
    app.on('fail', function onFail (app, test) {
      log('# :(', test.title)
      log('not ok', test.index, '-', test.title)

      var err = stackdata(test.reason, app.options)

      log('  ---')
      log('  name:', err.name)

      if (hasOwn(err, 'message') && err.message.length) {
        log('  message:', err.message)
      }
      if (hasOwn(err, 'expected')) {
        log('  expected:', util.inspect(err.expected))
      }
      if (hasOwn(err, 'actual')) {
        log('  actual:', util.inspect(err.actual))
      }
      /* istanbul ignore else */
      if (hasOwn(err, 'at')) {
        log('  at:', err.at)
      } else {
        app.options.showStack = true
      }

      if (app.options.showStack) {
        log('  stack:')
        err.stack.split('\n').slice(1).map(function (str) {
          log(str)
        })
      }

      log('  ...')
    })

    app.once('finish', function finish (app) {
      var stats = app.stats || app.options.stats

      log('')
      log('1..' + stats.count)
      log('# tests', stats.count)
      log('# pass', stats.pass)

      if (stats.fail) {
        log('# fail', stats.fail)
        log('')
      } else {
        log('')
        log('# ok')
      }
    })

    return app
  }
}

function hasOwn (self, key) {
  return Object.prototype.hasOwnProperty.call(self, key)
}