const includes = require("lodash/includes"); const readdir = require("fs-readdir-recursive"); const helper = require("babel-helper-fixtures"); const assert = require("assert"); const rimraf = require("rimraf"); const outputFileSync = require("output-file-sync"); const child = require("child_process"); const merge = require("lodash/merge"); const path = require("path"); const chai = require("chai"); const fs = require("fs"); const fixtureLoc = path.join(__dirname, "fixtures"); const tmpLoc = path.join(__dirname, "tmp"); const fileFilter = function(x) { return x !== ".DS_Store"; }; const presetLocs = [ path.join(__dirname, "../../babel-preset-es2015"), path.join(__dirname, "../../babel-preset-react"), ].join(","); const pluginLocs = [ path.join(__dirname, "/../../babel-plugin-transform-strict-mode"), path.join(__dirname, "/../../babel-plugin-transform-es2015-modules-commonjs"), ].join(","); const readDir = function(loc, filter) { const files = {}; if (fs.existsSync(loc)) { readdir(loc, filter).forEach(function(filename) { files[filename] = helper.readFile(path.join(loc, filename)); }); } return files; }; const saveInFiles = function(files) { // Place an empty .babelrc in each test so tests won't unexpectedly get to repo-level config. outputFileSync(".babelrc", "{}"); Object.keys(files).forEach(function(filename) { const content = files[filename]; outputFileSync(filename, content); }); }; const assertTest = function(stdout, stderr, opts) { const expectStderr = opts.stderr.trim(); stderr = stderr.trim(); if (opts.stderr) { if (opts.stderrContains) { assert.ok( includes(stderr, expectStderr), "stderr " + JSON.stringify(stderr) + " didn't contain " + JSON.stringify(expectStderr), ); } else { chai.expect(stderr).to.equal(expectStderr, "stderr didn't match"); } } else if (stderr) { throw new Error("stderr:\n" + stderr); } const expectStdout = opts.stdout.trim(); stdout = stdout.trim(); stdout = stdout.replace(/\\/g, "/"); if (opts.stdout) { if (opts.stdoutContains) { assert.ok( includes(stdout, expectStdout), "stdout " + JSON.stringify(stdout) + " didn't contain " + JSON.stringify(expectStdout), ); } else { chai.expect(stdout).to.equal(expectStdout, "stdout didn't match"); } } else if (stdout) { throw new Error("stdout:\n" + stdout); } if (opts.outFiles) { const actualFiles = readDir(path.join(tmpLoc)); Object.keys(actualFiles).forEach(function(filename) { if (!opts.inFiles.hasOwnProperty(filename)) { const expect = opts.outFiles[filename]; const actual = actualFiles[filename]; chai.expect(expect, "Output is missing: " + filename).to.not.be .undefined; if (expect) { chai .expect(actual) .to.equal(expect, "Compiled output does not match: " + filename); } } }); Object.keys(opts.outFiles).forEach(function(filename) { chai .expect(actualFiles, "Extraneous file in output: " + filename) .to.contain.key(filename); }); } }; const buildTest = function(binName, testName, opts) { const binLoc = path.join(__dirname, "../lib", binName); return function(callback) { clear(); saveInFiles(opts.inFiles); let args = [binLoc]; args.push("--presets", presetLocs, "--plugins", pluginLocs); args.push("--only", "../../../../packages/*/test"); args = args.concat(opts.args); const spawn = child.spawn(process.execPath, args); let stderr = ""; let stdout = ""; spawn.stderr.on("data", function(chunk) { stderr += chunk; }); spawn.stdout.on("data", function(chunk) { stdout += chunk; }); spawn.on("close", function() { let err; try { assertTest(stdout, stderr, opts); } catch (e) { err = e; } if (err) { err.message = args.map(arg => `"${arg}"`).join(" ") + ": " + err.message; } callback(err); }); if (opts.stdin) { spawn.stdin.write(opts.stdin); spawn.stdin.end(); } }; }; const clear = function() { process.chdir(__dirname); if (fs.existsSync(tmpLoc)) rimraf.sync(tmpLoc); fs.mkdirSync(tmpLoc); process.chdir(tmpLoc); }; fs.readdirSync(fixtureLoc).forEach(function(binName) { if (binName[0] === ".") return; const suiteLoc = path.join(fixtureLoc, binName); describe("bin/" + binName, function() { fs.readdirSync(suiteLoc).forEach(function(testName) { if (testName[0] === ".") return; const testLoc = path.join(suiteLoc, testName); const opts = { args: [], }; const optionsLoc = path.join(testLoc, "options.json"); if (fs.existsSync(optionsLoc)) merge(opts, require(optionsLoc)); ["stdout", "stdin", "stderr"].forEach(function(key) { const loc = path.join(testLoc, key + ".txt"); if (fs.existsSync(loc)) { opts[key] = helper.readFile(loc); } else { opts[key] = opts[key] || ""; } }); opts.outFiles = readDir(path.join(testLoc, "out-files"), fileFilter); opts.inFiles = readDir(path.join(testLoc, "in-files"), fileFilter); const babelrcLoc = path.join(testLoc, ".babelrc"); if (fs.existsSync(babelrcLoc)) { // copy .babelrc file to tmp directory opts.inFiles[".babelrc"] = helper.readFile(babelrcLoc); } it(testName, buildTest(binName, testName, opts)); }); }); });