avajs / ava

Node.js test runner that lets you develop with confidence šŸš€
MIT License
20.72k stars 1.41k forks source link

Babel plugins not loading when overridden in package.json AVA section #674

Closed dcousineau closed 8 years ago

dcousineau commented 8 years ago

Description

The documentation discusses overriding Babel configuration in the AVA section. However it appears at least the "plugins" if not the entire configuration is ignored in favor of .babelrc or the defaults.

Specifically: We need babel-plugin-rewire for our tests so we setup the AVA section of our package.json to look like:

{
  //...
  "ava": {
    "files": [
      "./tests/client/**/*.test.js",
      "./tests/server/**/*.test.js"
    ],
    "source": [
      "./src/client/scripts/**/*.{js,jsx}",
      "!./src/client/scripts/*Entry.js",
      "./src/server/**/*.js"
    ],
    "failFast": true,
    "tap": false,
    "require": [
      "babel-register",
      "babel-polyfill"
    ],
    "babel": {
      "presets": ["es2015", "react", "stage-0"],
      "plugins": ["rewire"]
    }
  },
  //...
}

With our .babelrc looking like:

{
  "presets": ["es2015", "react", "stage-0"]
}

However the tests would fail saying TypeError: Cannot read property 'Rewire' of undefined which indicates the plugin isn't running.

When I update the .babelrc file to include the "plugins": ["rewire"] it works.

Dropping console.logs in the rewire plugin inside of node_modules confirms the plugin doesn't even attempt to load.

I dropped some console logs into caching-precompiler.js in the _createTransform method and it IS getting the configuration I expect from package.json so the failure may be on caching-transform's part.

Environment

Node.js v5.9.0 darwin 15.4.0 AVA 0.13.0

dcousineau commented 8 years ago

Additional notes

So after I submit this issue I set "bablerc": false in the override because I think I'm an idiot and remove rewire from the .babelrc file and the tests work, but I get a weird behavior:

./node_modules/.bin/ava --verbose

Initializing CachingPrecompiler with: { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins: [ 'rewire' ] }
_createTransform with: { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins: [ 'rewire' ] }
++ About to actually execute transform...
:: buildOptions()
Overriding Babel Config { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins: [ 'rewire' ] }
Final Options { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ],
  inputSourceMap: null,
  filename: '/Users/dcousineau/Projects/grovo/frontend/tests/client/components/primitives-utilities.test.js',
  sourceMaps: true,
  ast: false }
Rewire is loaded and working...
++ Finished transform
++ About to actually execute transform...
:: buildOptions()
Overriding Babel Config { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ] }
Final Options { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ],
  inputSourceMap: null,
  filename: '/Users/dcousineau/Projects/grovo/frontend/tests/client/components/progress-meter.test.js',
  sourceMaps: true,
  ast: false }
++ Finished transform
++ About to actually execute transform...
:: buildOptions()
Overriding Babel Config { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ] }
Final Options { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ],
  inputSourceMap: null,
  filename: '/Users/dcousineau/Projects/grovo/frontend/tests/client/config/config.test.js',
  sourceMaps: true,
  ast: false }
++ Finished transform
++ About to actually execute transform...
:: buildOptions()
Overriding Babel Config { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ] }
Final Options { babelrc: false,
  presets: [ 'es2015', 'react', 'stage-0' ],
  plugins:
   [ 'rewire',
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] },
     { visitor: [Object] },
     { __esModule: true, default: [Function], definitions: [Object] } ],
  inputSourceMap: null,
  filename: '/Users/dcousineau/Projects/grovo/frontend/tests/client/reducers/ground-control.test.js',
  sourceMaps: true,
  ast: false }
++ Finished transform

And it repeats slowly accumulating for each file AVA loads

Obviously the console logs are from some that I dropped trying to figure out how AVA is working internally, a copy of my file can be found in this gist

dcousineau commented 8 years ago

I think the/a bug is here in the options.plugins.push. Possibly a .concat wouldn't leak between executions?

dcousineau commented 8 years ago

That helps a lot actually, PR incoming

jamestalmage commented 8 years ago

@dcousineau The rewire plugin is generally used on sources, not tests. AVA automatically transpiles tests for you, but not sources. You still need to use .babelrc and --require babel-register to transpile sources.

There are other issues where we are discussing solutions:

dcousineau commented 8 years ago

I'll dig in further thanks!

dcousineau commented 8 years ago

@jamestalmage aha I get it now. I'm curious, do you think there'd be a way to provide configuration for the babel-register for the sources?

In the mean time I'm making my webpack config force its own babel config and will use babelrc to include the rewire plugin, in general I only want rewire plugin operating in a testing context but not when building the client.

jamestalmage commented 8 years ago

in general I only want rewire plugin operating in a testing context but not when building the client.

Ah, I see your dilemma. We still need to implement an extends option for your babel config:

// package.json
{
  "ava": {
    "babel" : {
      "extends": "./babelrc",
      "plugins": ["rewire"]
    }
  }
}

It was discussed along with #573, but never got implemented.

dcousineau commented 8 years ago

@jamestalmage if and only if I can specify the babel config for the source files as well (not just the test files) which I think is my real ask. (but an extends would be great as well)

Should I close this issue or rename it as a feature request? After doing some other things and sleeping on it I realize this is not a bug given what you've told me about the differences in transpiling test files and transpiling source files.

jamestalmage commented 8 years ago

If you want the same config for both tests and sources, do babel: "inherit" in your config. The extends option is used for adding some extra transforms to test files that you don't want impacting sources.

With rewire you have an interesting case where you want to transpile your sources differently during testing than during production/publishing. I would recommend checking out the env option in .babelrc and setting an environment variable.

novemberborn commented 8 years ago

The extends approach that @jamestalmage suggested should actually work. The env approach is another avenue you could try.

@dcousineau I'm closing this for now. Please feel free to reopen if you still have issues.

kosmotaur commented 8 years ago

I have the exact same use case, trying to use babel-plugin-rewire only in tests. extends unfortunately failed, but the env way worked well. Not ideal, since I am trying for the project to be fully environment agnostic, but it unblocked me.

jamestalmage commented 8 years ago

Your best bet is to have it default to installing rewire / everything you need for testing. That way your most common operation, running tests, needs no special environment variable set.

Use envs to turn off that stuff when you go to build.

kosmotaur commented 8 years ago

Good point, apply the env to the least common tasks to remove redundant bits. One more downside is having to repeat sections of .babelrc, in my case, at the moment:

{
  "presets": [
    "es2015",
    "react",
    "stage-2"
  ],
  "plugins": [
    "transform-object-rest-spread"
  ],
  "env": {
    "test": {
      "plugins": [
        "transform-object-rest-spread",
        "rewire"
      ]
    }
  }
}

But that's just Babel now. Anyhow, things work, testing away! šŸ˜‚

djskinner commented 7 years ago

I've found that I have to do the same as @kosmotaur:

{
  "presets": [
    ["env", {
        "loose": true,
        "modules": false,
        "useBuiltIns": true
    }],
    "stage-0",
    "react"
  ],
  "plugins": [],
  "env": {
      "test": {
        "presets": [
            ["env", {
                "loose": true,
                "modules": "commonjs",
                "useBuiltIns": true
            }],
            "stage-0",
            "react"
        ]
      }
  }
}

For my main build I want babel to ignore modules as to allow Webpack 2 tree-shaking but need babel to transpile them in a test context.

Not matter what I tried in pkg.ava.babel I couldn't get it to work. It seems like the original env preset configuration was still being used.

novemberborn commented 7 years ago

@djskinner did you try specifying the transform-es2015-modules-commonjs plugin in pkg.ava.babel? I'm not sure if redefining presets with different options works the way you're expecting it to.

djskinner commented 7 years ago

Yes, you're right about the presets getting replace as I'd expected.

I ended up doing this:

// .babelrc
{
  "presets": [
    "./.babelrc.js"
  ]
}

// .babelrc.js
const env = process.env.BABEL_ENV || process.env.NODE_ENV || 'development'
const browserlist = ["last 2 versions"]

const getTargets = (env) => {
    if (env === 'node') return { "node": true };
    if (env === 'production') return { "browsers": browserlist, "uglify": true };
    return { "browsers": browserlist }
}

const targets = getTargets(env)

module.exports = {
    presets: [
        ["env", {
            targets,
            "loose": true,
            "modules": env === 'modules' ? 'commonjs' : false,
            "useBuiltIns": true
        }],
        "stage-0",
        "react"
    ]
}