lib/reporters/tap.js

const YAML = require('yaml');
const file = require('../file.js').file;

/**
 * @module pete/lib/reporters/tap
 */
module.exports = createTAP;

/**
 * @private
 */
const TAP_VERSION = 14;

/**
 * TAP
 *
 * @external TAP
 * @see {@link https://testanything.org/tap-version-14-specification.html}
 */

/**
 * Create and return report function that will output reports in TAP format.
 *
 * @see {@link external:TAP}
 * @alias module:pete/lib/reporters/tap
 * @param {object} [options]
 * @param {object} [options.out]        path to file that should be created
 * @param {object} [options.callback]   to call once on `out` stream `close` event
 * @return {module:pete/lib/getReporters~report}
 */
function createTAP (options) {
	var index = 0;
	var out = (options && options.out) || process.stdout;
	var callback = (options && options.callback) || null;

	if (typeof out === 'string') {
		try {
			out = file(out, true);
		}
		catch (e) {
			console.error(e);
			out = process.stderr;
		}
	}

	if (typeof callback === 'function') {
		out.once('close', options.callback);
	}

	return function tap (err, report) {
		if (index < 0) {
			console.error(new Error('TAP reporter called after it was closed'));
			return;
		}

		if (index === 0) {
			out.write(`TAP version ${TAP_VERSION}\n`);
		}

		if (!err && !report) {
			out.end(`1..${index}${index < 1 ? ' # Skipped' : ''}\n`);
			index = -1;
			return;
		}

		index++;

		var mode = report?.mode ? `${report.mode} ` : '';
		out.write(`${err ? 'not ' : ''}ok ${index} - ${report?.name} # ${mode}${report?.summary || ''}`);

		var info = {
			message : err ? err.stack : 'Report',
			severity: err ? 'fail' : 'comment',
			data    : report
		};

		out.write(`\n  ---\n  ${YAML.stringify(info).replace(/\n/g, '\n  ')}...\n`);
	};
}