UNPKG

tad

Version:
130 lines (116 loc) 3.97 kB
/* eslint max-lines: "off" */ "use strict"; var spread = require("es5-ext/function/#/spread") , deferred = require("deferred") , path = require("path") , commonPath = require("path2/common") , runInContext = require("vm").runInContext , out = require("./lib/console") , configure = require("./lib/configure") , load = require("./lib/load") , run = require("./lib/run"); var resolve = path.resolve, map = Array.prototype.map, suite, isError; isError = function (e, context) { if (e instanceof Error) return true; if (context !== global) { return runInContext("(function () { return this instanceof Error; })", context).call(e); } return false; }; suite = { init: function (paths, options) { var conf, d, projectRoot; d = deferred(); paths = map.call(paths, function (testPath) { return resolve(testPath); }); this.resolve = d.resolve; this.console = out(options); this.tail = deferred(null); if (paths.length > 1) { projectRoot = commonPath.apply(null, paths); this.rindex = projectRoot ? projectRoot.length + 1 : 0; } else if (paths.length) { this.rindex = paths[0].length + 1; } conf = configure(paths); conf("data", this.ondata.bind(this)); conf("end", this.onend.bind(this)); return d.promise; }, ondata: function () { this.tail = this.tail(spread.call(this.process).bind(this, arguments)); }, process: function (modulePath, fpath, tpath, context) { var pname = modulePath.slice(this.rindex), fname, logger, testModuleConfig, d; d = deferred(); this.console.break(); if (fpath instanceof Error) { // Wrong path this.console.error(pname, null, fpath); return d.resolve(); } fname = fpath.slice(this.rindex); if (tpath instanceof Error) { if (tpath.type === "testfile") { // Input is a test file, ignore return d.resolve(); } // Could not assume test file path (not within package) // or there were problems with obtaining context this.console.error(pname, fname, tpath); return d.resolve(); } // Configured ok, load files testModuleConfig = load(fpath, tpath, context); // Any files missing, any evaluation errors ? if (testModuleConfig.testee === undefined) { // File not accessible this.console.error(pname, fname, "Couldn't load module '" + fpath + "'"); return d.resolve(); } if (isError(testModuleConfig.test, context)) { this.console.error(pname, fname, testModuleConfig.test); return d.resolve(); } if (isError(testModuleConfig.testee, context)) { this.console.error(pname, fname, testModuleConfig.testee); return d.resolve(); } if (!testModuleConfig.test) { this.console.error(pname, fname, "Tests could not be loaded, tried '" + tpath + "'"); return d.resolve(); } // Loaded ok, run tests logger = run(testModuleConfig.testee, testModuleConfig.test); logger.on( "data", function (testResult) { if (d.resolved) { var error = new Error( "Unexpected state: Assertions are issued after suite finalized test run" ); // Create error in test context (to expose proper stack trace) // Throw in other context to avoid catch clause process.nextTick(function () { throw error; }); return; } var name = [fname].concat(testResult.msg); if (testResult.type === "pass") { name.push(testResult.data); } else if (testResult.type === "fail" && testResult.data.operator) { name.push(testResult.data.message); } name = name.filter(Boolean).join(": "); this.console[testResult.type](fname, name, testResult.data); }.bind(this) ); logger.on("end", function () { d.resolve(); }); return d.promise; }, onend: function () { this.tail(this.end.bind(this)).done(); delete this.tail; }, end: function () { this.console.end(); this.resolve(this); } }; module.exports = function (paths, options) { return Object.create(suite).init(paths, options); };