import assert from "assert"; import fs from "fs"; import path from "path"; import buildConfigChain from "../lib/config/build-config-chain"; function fixture() { const args = [__dirname, "fixtures", "config"]; for (let i = 0; i < arguments.length; i++) { args.push(arguments[i]); } return path.join.apply(path, args); } function base() { return process.cwd(); } describe("buildConfigChain", function() { let oldBabelEnv; let oldNodeEnv; beforeEach(function() { oldBabelEnv = process.env.BABEL_ENV; oldNodeEnv = process.env.NODE_ENV; delete process.env.BABEL_ENV; delete process.env.NODE_ENV; }); afterEach(function() { process.env.BABEL_ENV = oldBabelEnv; process.env.NODE_ENV = oldNodeEnv; }); describe("ignore", () => { it("should ignore files that match", () => { const chain = buildConfigChain({ filename: fixture("nonexistant-fake", "src.js"), babelrc: false, ignore: [ fixture("nonexistant-fake", "src.js"), // We had a regression where multiple ignore patterns broke things, so // we keep some extra random items in here. fixture("nonexistant-fake", "other.js"), fixture("nonexistant-fake", "misc.js"), ], }); assert.equal(chain, null); }); it("should not ignore files that don't match", () => { const chain = buildConfigChain({ filename: fixture("nonexistant-fake", "src.js"), babelrc: false, ignore: [ fixture("nonexistant-fake", "other.js"), fixture("nonexistant-fake", "misc.js"), ], }); const expected = [ { type: "arguments", options: { filename: fixture("nonexistant-fake", "src.js"), babelrc: false, ignore: [ fixture("nonexistant-fake", "other.js"), fixture("nonexistant-fake", "misc.js"), ], }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); }); describe("only", () => { it("should ignore files that don't match", () => { const chain = buildConfigChain({ filename: fixture("nonexistant-fake", "src.js"), babelrc: false, only: [ fixture("nonexistant-fake", "other.js"), fixture("nonexistant-fake", "misc.js"), ], }); assert.equal(chain, null); }); it("should not ignore files that match", () => { const chain = buildConfigChain({ filename: fixture("nonexistant-fake", "src.js"), babelrc: false, only: [ fixture("nonexistant-fake", "src.js"), fixture("nonexistant-fake", "misc.js"), ], }); const expected = [ { type: "arguments", options: { filename: fixture("nonexistant-fake", "src.js"), babelrc: false, only: [ fixture("nonexistant-fake", "src.js"), fixture("nonexistant-fake", "misc.js"), ], }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); }); describe("ignore/only", () => { it("should ignore files that match ignore and don't match only", () => { const chain = buildConfigChain({ filename: fixture("nonexistant-fake", "src.js"), babelrc: false, ignore: [fixture("nonexistant-fake", "src.js")], only: [fixture("nonexistant-fake", "src.js")], }); assert.equal(chain, null); }); }); describe("caching", function() { describe("programmatic options", function() { it("should not cache the input options by identity", () => { const comments = false; const chain1 = buildConfigChain({ comments }); const chain2 = buildConfigChain({ comments }); assert.equal(chain1.length, 1); assert.equal(chain2.length, 1); assert.notStrictEqual(chain1[0], chain2[0]); }); it("should cache the env options by identity", () => { process.env.NODE_ENV = "foo"; const env = { foo: { comments: false, }, }; const chain1 = buildConfigChain({ env }); const chain2 = buildConfigChain({ env }); assert.equal(chain1.length, 2); assert.equal(chain2.length, 2); assert.strictEqual(chain1[0], chain2[0]); assert.strictEqual(chain1[1], chain2[1]); }); it("should cache the plugin options by identity", () => { const plugins = []; const chain1 = buildConfigChain({ plugins }); const chain2 = buildConfigChain({ plugins }); assert.equal(chain1.length, 1); assert.equal(chain2.length, 1); assert.strictEqual(chain1[0], chain2[0]); }); it("should cache the presets options by identity", () => { const presets = []; const chain1 = buildConfigChain({ presets }); const chain2 = buildConfigChain({ presets }); assert.equal(chain1.length, 1); assert.equal(chain2.length, 1); assert.strictEqual(chain1[0], chain2[0]); }); it("should not cache the presets options with passPerPreset", () => { const presets = []; const chain1 = buildConfigChain({ presets }); const chain2 = buildConfigChain({ presets, passPerPreset: true }); const chain3 = buildConfigChain({ presets, passPerPreset: false }); assert.equal(chain1.length, 1); assert.equal(chain2.length, 1); assert.equal(chain3.length, 1); assert.notStrictEqual(chain1[0], chain2[0]); assert.strictEqual(chain1[0], chain3[0]); assert.notStrictEqual(chain2[0], chain3[0]); }); }); describe("config file options", function() { function touch(filepath) { const s = fs.statSync(filepath); fs.utimesSync( filepath, s.atime, s.mtime + Math.random() > 0.5 ? 1 : -1, ); } it("should cache package.json files by mtime", () => { const filename = fixture( "complex-plugin-config", "config-identity", "pkg", "src.js", ); const pkgJSON = fixture( "complex-plugin-config", "config-identity", "pkg", "package.json", ); const chain1 = buildConfigChain({ filename }); const chain2 = buildConfigChain({ filename }); touch(pkgJSON); const chain3 = buildConfigChain({ filename }); const chain4 = buildConfigChain({ filename }); assert.equal(chain1.length, 3); assert.equal(chain2.length, 3); assert.equal(chain3.length, 3); assert.equal(chain4.length, 3); assert.equal(chain1[1].alias, pkgJSON); assert.equal(chain2[1].alias, pkgJSON); assert.equal(chain3[1].alias, pkgJSON); assert.equal(chain4[1].alias, pkgJSON); assert.strictEqual(chain1[1], chain2[1]); // Identity changed after touch(). assert.notStrictEqual(chain3[1], chain1[1]); assert.strictEqual(chain3[1], chain4[1]); }); it("should cache .babelrc files by mtime", () => { const filename = fixture( "complex-plugin-config", "config-identity", "babelrc", "src.js", ); const babelrcFile = fixture( "complex-plugin-config", "config-identity", "babelrc", ".babelrc", ); const chain1 = buildConfigChain({ filename }); const chain2 = buildConfigChain({ filename }); touch(babelrcFile); const chain3 = buildConfigChain({ filename }); const chain4 = buildConfigChain({ filename }); assert.equal(chain1.length, 3); assert.equal(chain2.length, 3); assert.equal(chain3.length, 3); assert.equal(chain4.length, 3); assert.equal(chain1[1].alias, babelrcFile); assert.equal(chain2[1].alias, babelrcFile); assert.equal(chain3[1].alias, babelrcFile); assert.equal(chain4[1].alias, babelrcFile); assert.strictEqual(chain1[1], chain2[1]); // Identity changed after touch(). assert.notStrictEqual(chain3[1], chain1[1]); assert.strictEqual(chain3[1], chain4[1]); }); it("should cache .babelignore files by mtime", () => { const filename = fixture( "complex-plugin-config", "config-identity", "babelignore", "src.js", ); const babelignoreFile = fixture( "complex-plugin-config", "config-identity", "babelignore", ".babelignore", ); const chain1 = buildConfigChain({ filename }); const chain2 = buildConfigChain({ filename }); touch(babelignoreFile); const chain3 = buildConfigChain({ filename }); const chain4 = buildConfigChain({ filename }); assert.equal(chain1.length, 6); assert.equal(chain2.length, 6); assert.equal(chain3.length, 6); assert.equal(chain4.length, 6); assert.equal(chain1[4].alias, babelignoreFile); assert.equal(chain2[4].alias, babelignoreFile); assert.equal(chain3[4].alias, babelignoreFile); assert.equal(chain4[4].alias, babelignoreFile); assert.strictEqual(chain1[4], chain2[4]); // Identity changed after touch(). assert.notStrictEqual(chain3[4], chain1[4]); assert.strictEqual(chain3[4], chain4[4]); }); it("should cache .babelrc.js files programmable behavior", () => { const filename = fixture( "complex-plugin-config", "config-identity", "babelrc-js", "src.js", ); const babelrcFile = fixture( "complex-plugin-config", "config-identity", "babelrc-js", ".babelrc.js", ); const chain1 = buildConfigChain({ filename }); const chain2 = buildConfigChain({ filename }); process.env.NODE_ENV = "new-env"; const chain3 = buildConfigChain({ filename }); const chain4 = buildConfigChain({ filename }); assert.equal(chain1.length, 3); assert.equal(chain2.length, 3); assert.equal(chain3.length, 3); assert.equal(chain4.length, 3); assert.equal(chain1[1].alias, babelrcFile); assert.equal(chain2[1].alias, babelrcFile); assert.equal(chain3[1].alias, babelrcFile); assert.equal(chain4[1].alias, babelrcFile); assert.strictEqual(chain1[1], chain2[1]); // Identity changed after changing the NODE_ENV. assert.notStrictEqual(chain3[1], chain1[1]); assert.strictEqual(chain3[1], chain4[1]); }); }); }); it("dir1", function() { const chain = buildConfigChain({ filename: fixture("dir1", "src.js"), }); const expected = [ { type: "file", options: { plugins: ["extended"], }, alias: fixture("extended.babelrc.json"), dirname: fixture(), }, { type: "file", options: { extends: "./extended.babelrc.json", plugins: ["root"], }, alias: fixture(".babelrc"), dirname: fixture(), }, { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "arguments", options: { filename: fixture("dir1", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("dir2", function() { const chain = buildConfigChain({ filename: fixture("dir2", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { plugins: ["dir2"], }, alias: fixture("dir2", ".babelrc"), dirname: fixture("dir2"), }, { type: "arguments", options: { filename: fixture("dir2", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("dir3", function() { const chain = buildConfigChain({ filename: fixture("dir3", "src.js"), }); const expected = [ { type: "file", options: { plugins: ["extended"], }, alias: fixture("extended.babelrc.json"), dirname: fixture(), }, { type: "file", options: { extends: "./extended.babelrc.json", plugins: ["root"], }, alias: fixture(".babelrc"), dirname: fixture(), }, { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "arguments", options: { filename: fixture("dir3", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("env - base", function() { const chain = buildConfigChain({ filename: fixture("env", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { env: { bar: { plugins: ["env-bar"], }, foo: { plugins: ["env-foo"], }, }, plugins: ["env-base"], }, alias: fixture("env", ".babelrc"), dirname: fixture("env"), }, { type: "arguments", options: { filename: fixture("env", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("env - foo", function() { process.env.NODE_ENV = "foo"; const chain = buildConfigChain({ filename: fixture("env", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { env: { bar: { plugins: ["env-bar"], }, foo: { plugins: ["env-foo"], }, }, plugins: ["env-base"], }, alias: fixture("env", ".babelrc"), dirname: fixture("env"), }, { type: "env", options: { plugins: ["env-foo"], }, alias: fixture("env", ".babelrc.env.foo"), dirname: fixture("env"), }, { type: "arguments", options: { filename: fixture("env", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("env - bar", function() { process.env.NODE_ENV = "foo"; // overridden process.env.NODE_ENV = "bar"; const chain = buildConfigChain({ filename: fixture("env", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { env: { bar: { plugins: ["env-bar"], }, foo: { plugins: ["env-foo"], }, }, plugins: ["env-base"], }, alias: fixture("env", ".babelrc"), dirname: fixture("env"), }, { type: "env", options: { plugins: ["env-bar"], }, alias: fixture("env", ".babelrc.env.bar"), dirname: fixture("env"), }, { type: "arguments", options: { filename: fixture("env", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("env - foo", function() { process.env.NODE_ENV = "foo"; const chain = buildConfigChain({ filename: fixture("pkg", "src.js"), }); const expected = [ { type: "file", options: { plugins: ["pkg-plugin"], }, alias: fixture("pkg", "package.json"), dirname: fixture("pkg"), }, { type: "file", options: { ignore: ["pkg-ignore"], }, alias: fixture("pkg", ".babelignore"), dirname: fixture("pkg"), }, { type: "arguments", options: { filename: fixture("pkg", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("js-config", function() { const chain = buildConfigChain({ filename: fixture("js-config", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { plugins: ["foo", "bar"], }, alias: fixture("js-config", ".babelrc.js"), dirname: fixture("js-config"), }, { type: "arguments", options: { filename: fixture("js-config", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("js-config-function", function() { const chain = buildConfigChain({ filename: fixture("js-config-function", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { compact: true, }, alias: fixture("js-config-function", ".babelrc.js"), dirname: fixture("js-config-function"), }, { type: "arguments", options: { filename: fixture("js-config-function", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("js-config-default - should read transpiled export default", function() { const chain = buildConfigChain({ filename: fixture("js-config-default", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { plugins: ["foo", "bar"], }, alias: fixture("js-config-default", ".babelrc.js"), dirname: fixture("js-config-default"), }, { type: "arguments", options: { filename: fixture("js-config-default", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it("js-config-extended", function() { const chain = buildConfigChain({ filename: fixture("js-config-extended", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { plugins: ["extended"], }, alias: fixture("extended.babelrc.json"), dirname: fixture(), }, { type: "file", options: { extends: "../extended.babelrc.json", plugins: ["foo", "bar"], }, alias: fixture("js-config-extended", ".babelrc.js"), dirname: fixture("js-config-extended"), }, { type: "arguments", options: { filename: fixture("js-config-extended", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }); it( "json-pkg-config-no-babel - should not throw if" + " package.json doesn't contain a `babel` field", function() { const chain = buildConfigChain({ filename: fixture("json-pkg-config-no-babel", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { plugins: ["json"], }, alias: fixture("json-pkg-config-no-babel", ".babelrc"), dirname: fixture("json-pkg-config-no-babel"), }, { type: "arguments", options: { filename: fixture("json-pkg-config-no-babel", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); }, ); it("should not ignore file matching negated file pattern", function() { const chain = buildConfigChain({ filename: fixture("ignore-negate", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { ignore: ["*", "!src.js"], }, alias: fixture("ignore-negate", ".babelrc"), dirname: fixture("ignore-negate"), }, { type: "arguments", options: { filename: fixture("ignore-negate", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); const chain2 = buildConfigChain({ filename: fixture("ignore-negate", "src2.js"), }); assert.equal(chain2, null); }); it("should not ignore file matching negated folder pattern", function() { const chain = buildConfigChain({ filename: fixture("ignore-negate-folder", "folder", "src.js"), }); const expected = [ { type: "file", options: { ignore: ["root-ignore"], }, alias: fixture(".babelignore"), dirname: fixture(), }, { type: "file", options: { ignore: ["*", "!folder"], }, alias: fixture("ignore-negate-folder", ".babelrc"), dirname: fixture("ignore-negate-folder"), }, { type: "arguments", options: { filename: fixture("ignore-negate-folder", "folder", "src.js"), }, alias: "base", dirname: base(), }, ]; assert.deepEqual(chain, expected); const chain2 = buildConfigChain({ filename: fixture("ignore-negate-folder", "src2.js"), }); assert.equal(chain2, null); }); it( "js-json-config - should throw an error if both a .babelrc" + " and a .babelrc.js are present", function() { assert.throws(function() { buildConfigChain({ filename: fixture("js-json-config", "src.js"), }); }, /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*\.babelrc\.js/); }, ); it( "js-pkg-config - should throw an error if both a .babelrc.js" + " and a package.json with a babel field are present", function() { assert.throws(function() { buildConfigChain({ filename: fixture("js-pkg-config", "src.js"), }); }, /Multiple configuration files found\.(.|\n)*\.babelrc\.js(.|\n)*package\.json/); }, ); it( "json-pkg-config - should throw an error if both a .babelrc" + " and a package.json with a babel field are present", function() { assert.throws(function() { buildConfigChain({ filename: fixture("json-pkg-config", "src.js"), }); }, /Multiple configuration files found\.(.|\n)*\.babelrc(.|\n)*package\.json/); }, ); it("js-config-error", function() { assert.throws(function() { buildConfigChain({ filename: fixture("js-config-error", "src.js"), }); }, /Error while loading config/); }); it("js-config-error2", function() { assert.throws(function() { buildConfigChain({ filename: fixture("js-config-error2", "src.js"), }); }, /Configuration should be an exported JavaScript object/); }); it("js-config-error3", function() { assert.throws(function() { buildConfigChain({ filename: fixture("js-config-error3", "src.js"), }); }, /Configuration should be an exported JavaScript object/); }); it("json-config-error", function() { assert.throws(function() { buildConfigChain({ filename: fixture("json-config-error", "src.js"), }); }, /Error while parsing config/); }); });