2017-02-04 11:07:15 -05:00

198 lines
5.4 KiB
JavaScript

import * as babel from "babel-core";
import { buildExternalHelpers } from "babel-core";
import getFixtures from "babel-helper-fixtures";
import sourceMap from "source-map";
import codeFrame from "babel-code-frame";
import defaults from "lodash/defaults";
import includes from "lodash/includes";
import * as helpers from "./helpers";
import extend from "lodash/extend";
import merge from "lodash/merge";
import assert from "assert";
import chai from "chai";
import "babel-polyfill";
import fs from "fs";
import path from "path";
const babelHelpers = eval(buildExternalHelpers(null, "var"));
function wrapPackagesArray(type, names, optionsDir) {
return (names || []).map(function (val) {
if (typeof val === "string") val = [val];
// relative path (outside of monorepo)
if (val[0][0] === ".") {
if (!optionsDir) {
throw new Error("Please provide an options.json in test dir when using a " +
"relative plugin path.");
}
val[0] = path.resolve(optionsDir, val[0]);
}
// check node_modules/babel-x-y
else {
val[0] = __dirname + "/../../babel-" + type + "-" + val[0];
}
return val;
});
}
function run(task) {
const actual = task.actual;
const expect = task.expect;
const exec = task.exec;
const opts = task.options;
const optionsDir = task.optionsDir;
function getOpts(self) {
const newOpts = merge({
filename: self.loc,
}, opts);
newOpts.plugins = wrapPackagesArray("plugin", newOpts.plugins, optionsDir);
newOpts.presets = wrapPackagesArray("preset", newOpts.presets, optionsDir).map(function (val) {
if (val.length > 2) {
throw new Error("Unexpected extra options " + JSON.stringify(val.slice(2)) +
" passed to preset.");
}
return val;
});
return newOpts;
}
let execCode = exec.code;
let result;
let resultExec;
if (execCode) {
const execOpts = getOpts(exec);
const execDirName = path.dirname(exec.loc);
result = babel.transform(execCode, execOpts);
execCode = result.code;
try {
resultExec = runExec(execOpts, execCode, execDirName);
} catch (err) {
err.message = exec.loc + ": " + err.message;
err.message += codeFrame(execCode);
throw err;
}
}
let actualCode = actual.code;
const expectCode = expect.code;
if (!execCode || actualCode) {
result = babel.transform(actualCode, getOpts(actual));
if (
!expect.code && result.code && !opts.throws && fs.statSync(path.dirname(expect.loc)).isDirectory() &&
!process.env.CI
) {
console.log(`New test file created: ${expect.loc}`);
fs.writeFileSync(expect.loc, result.code);
} else {
actualCode = result.code.trim();
chai.expect(actualCode).to.be.equal(expectCode, actual.loc + " !== " + expect.loc);
}
}
if (task.sourceMap) {
chai.expect(result.map).to.deep.equal(task.sourceMap);
}
if (task.sourceMappings) {
const consumer = new sourceMap.SourceMapConsumer(result.map);
task.sourceMappings.forEach(function (mapping) {
const actual = mapping.original;
const expect = consumer.originalPositionFor(mapping.generated);
chai.expect({ line: expect.line, column: expect.column }).to.deep.equal(actual);
});
}
if (execCode && resultExec) {
return resultExec;
}
}
function runExec(opts, execCode, execDirname) {
const sandbox = {
...helpers,
babelHelpers,
assert: chai.assert,
transform: babel.transform,
opts,
exports: {},
require(id) {
return require(id[0] === "." ? path.resolve(execDirname, id) : id);
}
};
const fn = new Function(...Object.keys(sandbox), execCode);
return fn.apply(null, Object.values(sandbox));
}
export default function (
fixturesLoc: string,
name: string,
suiteOpts = {},
taskOpts = {},
dynamicOpts?: Function,
) {
const suites = getFixtures(fixturesLoc);
for (const testSuite of suites) {
if (includes(suiteOpts.ignoreSuites, testSuite.title)) continue;
describe(name + "/" + testSuite.title, function () {
for (const task of testSuite.tests) {
if (includes(suiteOpts.ignoreTasks, task.title) ||
includes(suiteOpts.ignoreTasks, testSuite.title + "/" + task.title)) continue;
it(task.title, !task.disabled && function () {
function runTask() {
run(task);
}
defaults(task.options, {
filenameRelative: task.expect.filename,
sourceFileName: task.actual.filename,
sourceMapTarget: task.expect.filename,
suppressDeprecationMessages: true,
babelrc: false,
sourceMap: !!(task.sourceMappings || task.sourceMap),
});
extend(task.options, taskOpts);
if (dynamicOpts) dynamicOpts(task.options, task);
const throwMsg = task.options.throws;
if (throwMsg) {
// internal api doesn't have this option but it's best not to pollute
// the options object with useless options
delete task.options.throws;
assert.throws(runTask, function (err) {
return throwMsg === true || err.message.indexOf(throwMsg) >= 0;
});
} else {
if (task.exec.code) {
const result = run(task);
if (result && typeof result.then === "function") {
return result;
}
} else {
runTask();
}
}
});
}
});
}
}