302 lines
10 KiB
JavaScript
302 lines
10 KiB
JavaScript
|
process.env.BLUEBIRD_WARNINGS = 0;
|
||
|
var assert = require("assert");
|
||
|
assert.equal(require.main, module);
|
||
|
var Promise = require("bluebird");
|
||
|
var build = require("./build.js");
|
||
|
var utils = require("./utils.js");
|
||
|
var tableLogger = utils.tableLogger;
|
||
|
var argv = require("optimist").argv;
|
||
|
var glob = Promise.promisify(require("glob"));
|
||
|
var path = require("path");
|
||
|
var mkdirp = Promise.promisify(require("mkdirp"));
|
||
|
var rimraf = Promise.promisify(require("rimraf"));
|
||
|
var jobRunner = require("./job-runner/job-runner.js");
|
||
|
var mochaRunner = require("./mocha_runner.js");
|
||
|
var fs = Promise.promisifyAll(require("fs"));
|
||
|
var testUtils = require("../test/mocha/helpers/util");
|
||
|
jobRunner.setVerbose(0);
|
||
|
// Random slowness after tests complete
|
||
|
function getTests(options) {
|
||
|
var g;
|
||
|
if (options.testName === "all") {
|
||
|
g = "./test/mocha/*.js";
|
||
|
} else if (options.testName === "aplus") {
|
||
|
g = "./test/mocha/[0-9].[0-9].[0-9].js";
|
||
|
} else if (options.testName.indexOf("*") >= 0) {
|
||
|
g = "./test/mocha/" + options.testName;
|
||
|
} else {
|
||
|
var testName = options.testName.replace(/^(\d)(\d)(\d)$/, "$1.$2.$3");
|
||
|
g = "./test/mocha/" + testName + ".js";
|
||
|
}
|
||
|
return glob(g).then(function(matches) {
|
||
|
return matches.filter(function(match) {
|
||
|
if (match.indexOf("generator") >= 0) {
|
||
|
return options.generators;
|
||
|
}
|
||
|
return true;
|
||
|
})
|
||
|
}).tap(function(m) {
|
||
|
if (m.length === 0) {
|
||
|
throw new Error("No test file matches: '" + options.testName + "'");
|
||
|
}
|
||
|
}).map(function(filePath, i) {
|
||
|
var name = path.basename(filePath);
|
||
|
return {
|
||
|
name: name,
|
||
|
path: filePath,
|
||
|
index: i,
|
||
|
nameMatcher: "\\b" +
|
||
|
name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") +
|
||
|
"\\b"
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function getColorForCoverage(coveragePct) {
|
||
|
var colorThresholds = {
|
||
|
95: "brightgreen",
|
||
|
85: "green",
|
||
|
80: "yellowgreen",
|
||
|
70: "yellow",
|
||
|
60: "red"
|
||
|
};
|
||
|
var values = Object.keys(colorThresholds).map(Number).sort(function(a, b) {
|
||
|
return b - a;
|
||
|
});
|
||
|
for (var i = 0; i < values.length; ++i) {
|
||
|
if (coveragePct >= values[i]) return colorThresholds[values[i].toString()];
|
||
|
}
|
||
|
return colorThresholds[values[values.length - 1].toString()];
|
||
|
}
|
||
|
|
||
|
function getCoverage() {
|
||
|
return utils.run("npm", ["run", "istanbul", "--", "report", "text-summary"]).then(function(result) {
|
||
|
var stdout = result.stdout;
|
||
|
var pctPattern = /(\d+\.\d+)%/g;
|
||
|
var matches = stdout.match(pctPattern);
|
||
|
var sum = matches.map(function(pct) {
|
||
|
return parseFloat(pct.replace(/[^0-9.]/g, ""))
|
||
|
}).reduce(function(a, b) {
|
||
|
return a + b;
|
||
|
}, 0);
|
||
|
var average = Math.round(sum / matches.length);
|
||
|
return average;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function generateCoverageBadge(coverage) {
|
||
|
var text = "coverage-" + coverage + "%";
|
||
|
var color = getColorForCoverage(coverage);
|
||
|
var imgSrc = "http://img.shields.io/badge/" + text + "-" + color + ".svg?style=flat";
|
||
|
var link = "http://petkaantonov.github.io/bluebird/coverage/debug/index.html";
|
||
|
var markdown = "[!["+text+"]("+imgSrc+")]("+link+")";
|
||
|
return markdown;
|
||
|
}
|
||
|
|
||
|
function writeCoverageFile(coverage, groupNumber) {
|
||
|
var dir = build.dirs.coverage;
|
||
|
var fileName = path.join(dir, "coverage-group" + groupNumber + ".json");
|
||
|
var json = JSON.stringify(coverage);
|
||
|
return fs.writeFileAsync(fileName, json, "utf8").thenReturn(fileName);
|
||
|
}
|
||
|
|
||
|
function needsFreshProcess(testName) {
|
||
|
return /regress|using|domain|multiple-copies|unhandled_rejections|nodeify/.test(testName) ||
|
||
|
testUtils.isOldNode && /api_exceptions|promisify/.test(testName);
|
||
|
}
|
||
|
|
||
|
function runTestGroup(testGroup, options, progress) {
|
||
|
return jobRunner.run(mochaRunner, {
|
||
|
isolated: !options.singleTest,
|
||
|
log: options.singleTest,
|
||
|
progress: progress,
|
||
|
context: {
|
||
|
testGroup: testGroup,
|
||
|
singleTest: options.singleTest,
|
||
|
fakeTimers: options.fakeTimers,
|
||
|
cover: options.cover
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function combineTests(tests) {
|
||
|
var arrays = new Array(jobRunner.CHILD_PROCESSES);
|
||
|
for (var i = 0; i < arrays.length; ++i) {
|
||
|
arrays[i] = [];
|
||
|
}
|
||
|
|
||
|
var initialLength = arrays.length;
|
||
|
for (var i = 0; i < tests.length; ++i) {
|
||
|
var test = tests[i];
|
||
|
if (needsFreshProcess(test.name)) {
|
||
|
arrays.push([test]);
|
||
|
} else {
|
||
|
arrays[i % initialLength].push(tests[i]);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return arrays;
|
||
|
}
|
||
|
|
||
|
var testName = "all";
|
||
|
if ("run" in argv) {
|
||
|
testName = (argv.run + "");
|
||
|
if (testName.indexOf("*") === -1) {
|
||
|
testName = testName.toLowerCase()
|
||
|
.replace( /\.js$/, "" )
|
||
|
.replace( /[^a-zA-Z0-9_\-.]/g, "" );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var options = {
|
||
|
generators: (function() {
|
||
|
try {
|
||
|
new Function("(function*(){})");
|
||
|
return true;
|
||
|
} catch (e) {
|
||
|
return false;
|
||
|
}
|
||
|
})() || !!argv.nw,
|
||
|
cover: !!argv["cover"],
|
||
|
testName: testName,
|
||
|
singleTest: false,
|
||
|
saucelabs: !!argv.saucelabs,
|
||
|
testBrowser: !!argv.saucelabs || !!argv.browser || !!argv.nw,
|
||
|
executeBrowserTests: !!argv.saucelabs || !!argv.nw || (typeof argv["execute-browser-tests"] === "boolean" ?
|
||
|
argv["execute-browser-tests"] : !!argv.browser),
|
||
|
openBrowser: typeof argv["open-browser"] === "boolean" ? argv["open-browser"] : true,
|
||
|
port: argv.port || 9999,
|
||
|
fakeTimers: typeof argv["fake-timers"] === "boolean"
|
||
|
? argv["fake-timers"] : true,
|
||
|
jsHint: typeof argv["js-hint"] === "boolean" ? argv["js-hint"] : true,
|
||
|
nw: !!argv.nw,
|
||
|
nwPath: argv["nw-path"]
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
if (options.cover && typeof argv["cover"] === "string") {
|
||
|
options.coverFormat = argv["cover"];
|
||
|
} else {
|
||
|
options.coverFormat = "html";
|
||
|
}
|
||
|
|
||
|
var jsHint = options.jsHint ? require("./jshint.js")() : Promise.resolve();
|
||
|
var tests = getTests(options);
|
||
|
var buildOpts = {
|
||
|
debug: true
|
||
|
};
|
||
|
if (options.testBrowser) {
|
||
|
buildOpts.browser = true;
|
||
|
buildOpts.minify = true;
|
||
|
}
|
||
|
var buildResult = build(buildOpts);
|
||
|
if (options.cover) {
|
||
|
var exclusions = ["assert.js", "captured_trace.js"];
|
||
|
var coverageInstrumentedRoot = build.ensureDirectory(build.dirs.instrumented,options.cover, true);
|
||
|
var coverageReportsRoot = mkdirp(build.dirs.coverage, true).then(function() {
|
||
|
return fs.readdirAsync(build.dirs.coverage);
|
||
|
}).map(function(fileName) {
|
||
|
var filePath = path.join(build.dirs.coverage, fileName);
|
||
|
if (path.extname(fileName).indexOf("json") === -1) {
|
||
|
return rimraf(filePath);
|
||
|
}
|
||
|
});
|
||
|
buildResult = Promise.join(coverageInstrumentedRoot, buildResult, coverageReportsRoot, function() {
|
||
|
return utils.run("npm", ["-v"]).then(function(result) {
|
||
|
var version = result.stdout.split(".").map(Number);
|
||
|
if (version[0] < 2) {
|
||
|
throw new Error("Npm version 2.x.x required, current version is " + result.stdout);
|
||
|
}
|
||
|
});
|
||
|
}).tap(function() {
|
||
|
var copyExclusions = Promise.map(exclusions, function(exclusion) {
|
||
|
var fromPath = path.join(build.dirs.debug, exclusion);
|
||
|
var toPath = path.join(build.dirs.instrumented, exclusion);
|
||
|
return fs.readFileAsync(fromPath, "utf8").then(function(contents) {
|
||
|
return fs.writeFileAsync(toPath, contents, "utf8");
|
||
|
});
|
||
|
});
|
||
|
var args = [
|
||
|
"run",
|
||
|
"istanbul",
|
||
|
"--",
|
||
|
"instrument",
|
||
|
"--output",
|
||
|
build.dirs.instrumented,
|
||
|
"--no-compact",
|
||
|
"--preserve-comments",
|
||
|
"--embed-source"
|
||
|
];
|
||
|
exclusions.forEach(function(x) {
|
||
|
args.push("-x", x);
|
||
|
});
|
||
|
args.push(build.dirs.debug);
|
||
|
var istanbul = utils.run("npm", args, null, true);
|
||
|
return Promise.all([istanbul, copyExclusions]);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var testResults = Promise.join(tests, buildResult, function(tests) {
|
||
|
var singleTest = tests.length === 1;
|
||
|
options.singleTest = singleTest;
|
||
|
process.stdout.write("\u001b[m");
|
||
|
if (options.testBrowser) {
|
||
|
return require("./browser_test_generator.js")(tests, options);
|
||
|
} else if (singleTest) {
|
||
|
return runTestGroup(tests, options);
|
||
|
} else {
|
||
|
utils.cursorTo(0, 0);
|
||
|
utils.clearScreenDown();
|
||
|
tableLogger.addTests(tests);
|
||
|
return Promise.map(combineTests(tests), function(testGroup, index) {
|
||
|
return runTestGroup(testGroup, options, function(test) {
|
||
|
if (test.failed) {
|
||
|
tableLogger.testFail(test);
|
||
|
} else {
|
||
|
tableLogger.testSuccess(test);
|
||
|
}
|
||
|
}).then(function(maybeCoverage) {
|
||
|
if (options.cover) {
|
||
|
return writeCoverageFile(maybeCoverage.result, index + 1);
|
||
|
}
|
||
|
})
|
||
|
}).then(function() {
|
||
|
var p = Promise.resolve();
|
||
|
if (options.cover) {
|
||
|
var coverage = getCoverage();
|
||
|
if (process.execPath.indexOf("iojs") >= 0 && testName === "all") {
|
||
|
p = p.return(coverage).then(generateCoverageBadge).then(console.log);
|
||
|
}
|
||
|
p = p.then(function() {
|
||
|
return utils.run("npm", ["run", "istanbul", "--", "report", options.coverFormat], null, true);
|
||
|
}).return(coverage).then(function(coverage) {
|
||
|
console.log("Total coverage " + coverage + "%");
|
||
|
});
|
||
|
}
|
||
|
console.log("All tests passed");
|
||
|
return p;
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
Promise.all([testResults, jsHint]).spread(function(_, jsHintResponse) {
|
||
|
if (jsHintResponse) {
|
||
|
console.log("JSHint:");
|
||
|
console.log(jsHintResponse.stdout);
|
||
|
console.log(jsHintResponse.stderr);
|
||
|
}
|
||
|
}).catch(function(e) {
|
||
|
if (e && e.stdout || e.stderr) {
|
||
|
console.log(e.stdout);
|
||
|
console.error(e.stderr);
|
||
|
}
|
||
|
|
||
|
if (!e || !e.stack) {
|
||
|
console.error(e + "");
|
||
|
} else {
|
||
|
console.error(e.noStackPrint ? e.message : e.stack);
|
||
|
}
|
||
|
process.exit(2);
|
||
|
});
|