1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
/* 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); };
|