Skip to content

Commit

Permalink
Include syntax-object-rest-spread in default Babel options for Node.j…
Browse files Browse the repository at this point in the history
…s >= 8.3.0

Fixes #1554.
  • Loading branch information
codeslikejaggars authored and novemberborn committed Oct 27, 2017
1 parent 035fd31 commit 37c9122
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 8 deletions.
6 changes: 6 additions & 0 deletions docs/recipes/babelrc.md
Expand Up @@ -15,6 +15,12 @@ There are multiple options for configuring how AVA transpiles your tests using B

AVA lets you use some nifty JavaScript features, like [async functions](https://github.com/avajs/ava#async-function-support). To make this work on older Node.js versions AVA transpiles the tests and helper files using the [`@ava/stage-4`](https://github.com/avajs/babel-preset-stage-4) Babel preset. This is great for projects where you do not use Babel for your source, but do want to use the newest JavaScript features for your tests.

### Using object rest/spread properties

As of Node.js [8.3.0](https://github.com/nodejs/node/blob/v8.3.0/doc/changelogs/CHANGELOG_V8.md#8.3.0) [object rest/spread properties](https://github.com/tc39/proposal-object-rest-spread) is supported directly. This new language feature however has not yet reached [stage 4](http://2ality.com/2015/11/tc39-process.html#stage-4-finished), which means that AVA won't support it by default. That said, if you're using Node.js 8.3.0 or newer, AVA will load the [`syntax-object-rest-spread`](https://www.npmjs.com/package/babel-plugin-syntax-object-rest-spread) plugin for you. This means you *can* use object rest/spread properties in your tests as long as you're not targeting older Node.js versions.

Note that if you customize the Babel configuration you'll have to explicitly specify the `syntax-object-rest-spread` plugin.

## Customizing how AVA transpiles your tests

You can override the default Babel configuration AVA uses for test transpilation in `package.json`. For example, the configuration below adds the Babel `rewire` plugin, and adds the Babel [`stage-3`](http://babeljs.io/docs/plugins/preset-stage-3/) preset.
Expand Down
8 changes: 8 additions & 0 deletions lib/babel-config.js
Expand Up @@ -6,6 +6,7 @@ const figures = require('figures');
const configManager = require('hullabaloo-config-manager');
const md5Hex = require('md5-hex');
const makeDir = require('make-dir');
const semver = require('semver');
const colors = require('./colors');

function validate(conf) {
Expand Down Expand Up @@ -99,6 +100,7 @@ function build(projectDir, cacheDir, userOptions, powerAssert) {

const baseOptions = {
babelrc: false,
plugins: [],
presets: [
['@ava/transform-test-files', {powerAssert}]
]
Expand All @@ -107,6 +109,12 @@ function build(projectDir, cacheDir, userOptions, powerAssert) {
baseOptions.presets.unshift('@ava/stage-4');
}

// Include object rest spread support for node versions that support it
// natively.
if (userOptions === 'default' && semver.satisfies(process.versions.node, '>= 8.3.0')) {
baseOptions.plugins.push('babel-plugin-syntax-object-rest-spread');
}

const baseConfig = configManager.createConfig({
dir: AVA_DIR, // Presets are resolved relative to this directory
hash: md5Hex(JSON.stringify(baseOptions)),
Expand Down
21 changes: 13 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -108,6 +108,7 @@
"ava-init": "^0.2.0",
"babel-core": "^6.17.0",
"babel-generator": "^6.26.0",
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"bluebird": "^3.0.0",
"caching-transform": "^1.0.0",
"chalk": "^2.0.1",
Expand Down Expand Up @@ -165,6 +166,7 @@
"require-precompiled": "^0.1.0",
"resolve-cwd": "^2.0.0",
"safe-buffer": "^5.1.1",
"semver": "^5.4.1",
"slash": "^1.0.0",
"source-map-support": "^0.4.0",
"stack-utils": "^1.0.1",
Expand Down
51 changes: 51 additions & 0 deletions test/babel-config.js
Expand Up @@ -9,6 +9,19 @@ const configManager = require('hullabaloo-config-manager');
const babelConfigHelper = require('../lib/babel-config');

const fixture = name => path.join(__dirname, 'fixture', name);
const setNodeVersion = value => Object.defineProperty(process.versions, 'node', {value});
const resetNodeVersion = setNodeVersion.bind(null, process.versions.node);

// Execute `run` with a given stubbed node version, then reset to the real
// version.
function withNodeVersion(version, run) {
setNodeVersion(version);
const promise = new Promise(resolve => {
resolve(run());
});
promise.then(resetNodeVersion, resetNodeVersion);
return promise;
}

test('uses default presets when userOptions is "default"', t => {
const userOptions = 'default';
Expand Down Expand Up @@ -46,6 +59,7 @@ test('uses options from babelrc when userOptions is "inherit"', t => {
t.same(options.presets, [require.resolve('@ava/babel-preset-stage-4')]);
const envOptions = options.env[configManager.currentEnv()];
t.same(envOptions, {
plugins: [],
presets: [
[
require.resolve('@ava/babel-preset-transform-test-files'),
Expand Down Expand Up @@ -82,6 +96,43 @@ test('uses userOptions for babel options when userOptions is an object', t => {
});
});

test('adds babel-plugin-syntax-object-rest-spread for node versions > 8.3.0', t => {
const projectDir = uniqueTempDir();
const cacheDir = path.join(projectDir, 'cache');

return withNodeVersion('9.0.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true))
.then(result => {
const options = result.getOptions();
t.same(options.plugins, [
require.resolve('babel-plugin-syntax-object-rest-spread')
]);
});
});

test('adds babel-plugin-syntax-object-rest-spread for node versions == 8.3.0', t => {
const projectDir = uniqueTempDir();
const cacheDir = path.join(projectDir, 'cache');

return withNodeVersion('8.3.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true))
.then(result => {
const options = result.getOptions();
t.same(options.plugins, [
require.resolve('babel-plugin-syntax-object-rest-spread')
]);
});
});

test('does not add babel-plugin-syntax-object-rest-spread for node versions < 8.3.0', t => {
const projectDir = uniqueTempDir();
const cacheDir = path.join(projectDir, 'cache');

return withNodeVersion('8.2.0', () => babelConfigHelper.build(projectDir, cacheDir, 'default', true))
.then(result => {
const options = result.getOptions();
t.same(options.plugins, []);
});
});

test('should disable power-assert when powerAssert is false', t => {
const userOptions = 'default';
const powerAssert = false;
Expand Down

2 comments on commit 37c9122

@sholladay
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@novemberborn any chance you could release this soon? Just a friendly nudge.

I am on Node 8.9.1 and writing tests that benefit a lot from object spread and was surprised when AVA blew up. I can confirm that this commit fixes it.

For context, Node 8.3 came out August 10th, and 8.9.0 with Long Term Support status came out October 31st, so it probably has good adoption by now.

@novemberborn
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sholladay yea we could do a release. I'm doing a bit of traveling at the moment so I'm not sure when I'll get around to it. Definitely not on this train's WiFi connection 😉

Please sign in to comment.