Permalink
Browse files

Add support for ava.config.js files

The config file must be placed next to the `package.json`. Config must not be present in both. The file should use ESM-`export default` to export a plain config object or a factory returning one. Config must be resolved synchronously.
  • Loading branch information...
good-idea authored and novemberborn committed May 30, 2018
1 parent 3533aba commit 16f474242880ea325fea792dbd11ae43bbe17c06
Showing with 296 additions and 30 deletions.
  1. +1 βˆ’1 docs/recipes/babel.md
  2. +1 βˆ’1 docs/recipes/es-modules.md
  3. +1 βˆ’1 docs/recipes/flow.md
  4. +1 βˆ’1 docs/recipes/jspm-systemjs.md
  5. +1 βˆ’1 docs/recipes/react.md
  6. +4 βˆ’5 docs/recipes/watch-mode.md
  7. +17 βˆ’5 lib/cli.js
  8. +58 βˆ’0 lib/load-config.js
  9. +1 βˆ’2 package-lock.json
  10. +1 βˆ’1 package.json
  11. +7 βˆ’11 profile.js
  12. +42 βˆ’1 readme.md
  13. +14 βˆ’0 test/cli.js
  14. +3 βˆ’0 test/fixture/load-config/factory-no-plain-return/ava.config.js
  15. +1 βˆ’0 test/fixture/load-config/factory-no-plain-return/package.json
  16. +5 βˆ’0 test/fixture/load-config/factory-no-promise-return/ava.config.js
  17. +1 βˆ’0 test/fixture/load-config/factory-no-promise-return/package.json
  18. +1 βˆ’0 test/fixture/load-config/no-default-export/ava.config.js
  19. +1 βˆ’0 test/fixture/load-config/no-default-export/package.json
  20. +1 βˆ’0 test/fixture/load-config/no-plain-config/ava.config.js
  21. +1 βˆ’0 test/fixture/load-config/no-plain-config/package.json
  22. +1 βˆ’0 test/fixture/load-config/no-promise-config/ava.config.js
  23. +1 βˆ’0 test/fixture/load-config/no-promise-config/package.json
  24. +5 βˆ’0 test/fixture/load-config/package-no-file-yes-factory/ava.config.js
  25. +1 βˆ’0 test/fixture/load-config/package-no-file-yes-factory/package.json
  26. +5 βˆ’0 test/fixture/load-config/package-no-file-yes/ava.config.js
  27. +1 βˆ’0 test/fixture/load-config/package-no-file-yes/package.json
  28. +6 βˆ’0 test/fixture/load-config/package-only/package.json
  29. +3 βˆ’0 test/fixture/load-config/package-yes-file-yes/ava.config.js
  30. +8 βˆ’0 test/fixture/load-config/package-yes-file-yes/package.json
  31. +1 βˆ’0 test/fixture/load-config/throws/ava.config.js
  32. +1 βˆ’0 test/fixture/load-config/throws/package.json
  33. +100 βˆ’0 test/load-config.js
View
@@ -10,7 +10,7 @@ If you are using Babel for your source files then you must also [configure sourc
## Customize how AVA compiles your test files
You can override the default Babel configuration AVA uses for test file compilation in `package.json`. For example, the configuration below adds support for JSX syntax and stage 3 features:
You can override the default Babel configuration AVA uses for test file compilation in `package.json` or `ava.config.js`. For example, the configuration below adds support for JSX syntax and stage 3 features:
```json
{
@@ -12,7 +12,7 @@ First, install [`esm`](https://github.com/standard-things/esm):
$ npm install esm
```
Configure it in your `package.json` file, and add it to AVA's `"require"` option as well. Make sure to add it as the first item:
Configure it in your `package.json` or `ava.config.js` file, and add it to AVA's `"require"` option as well. Make sure to add it as the first item:
```json
{
View
@@ -6,7 +6,7 @@ AVA comes bundled with a Flow definition file. This allows developers to leverag
This guide assumes you've already set up Flow for your project. Note that AVA's definition as been tested with version 0.69.0.
We recommend you use AVA's built-in Babel pipeline to strip Flow type annotations and declarations. AVA automatically applies your project's Babel configuration, so everything may just work without changes. Alternatively install [`@babel/plugin-transform-flow-strip-types`](https://www.npmjs.com/package/@babel/plugin-transform-flow-strip-types) and customize AVA's configuration in the `package.json` file as follows:
We recommend you use AVA's built-in Babel pipeline to strip Flow type annotations and declarations. AVA automatically applies your project's Babel configuration, so everything may just work without changes. Alternatively install [`@babel/plugin-transform-flow-strip-types`](https://www.npmjs.com/package/@babel/plugin-transform-flow-strip-types) and customize AVA's configuration in the `package.json` file (or the `ava.config.js` file) as follows:
```json
{
@@ -31,7 +31,7 @@ You will need to install the [AVA JSPM loader](https://github.com/skorlir/ava-js
```
$ npm install --save-dev ava-jspm-loader @babel/register
```
You will also need to update your AVA config in package.json to use the JSPM loader.
You will also need to update your AVA config in the `package.json` or `ava.config.js` to use the JSPM loader.
```json
{
View
@@ -6,7 +6,7 @@ Translations: [EspaΓ±ol](https://github.com/avajs/ava-docs/blob/master/es_ES/doc
AVA automatically extends your regular (project-level) Babel configuration. You should be able to use React in your test files without any additional configuration.
However if you want to set it up explicitly, add the preset to the test options in AVA's Babel pipeline by modifying your `package.json`:
However if you want to set it up explicitly, add the preset to the test options in AVA's Babel pipeline by modifying your `package.json` or `ava.config.js` file:
```json
{
@@ -45,7 +45,7 @@ And then use:
$ npm run watch:test
```
Finally you could configure AVA to *always* run in watch mode by setting the `watch` key in the [`ava` section of your `package.json`]:
Finally you could configure AVA to *always* run in watch mode by setting the `watch` key in the [`ava` section of your `package.json`, or `ava.config.js` file][config]:
```json
{
@@ -67,7 +67,7 @@ In AVA there's a distinction between *source files* and *test files*. As you can
By default AVA watches for changes to the test files, snapshot files, `package.json`, and any other `.js` files. It'll ignore files in [certain directories](https://github.com/novemberborn/ignore-by-default/blob/master/index.js) as provided by the [`ignore-by-default`] package.
You can configure patterns for the source files in the [`ava` section of your `package.json`] file, using the `source` key.
You can configure patterns for the source files in the [`ava` section of your `package.json`, or `ava.config.js` file][config], using the `source` key.
You can specify patterns to match files in the folders that would otherwise be ignored, e.g. use `node_modules/some-dependency/*.js` to specify all `.js` files in `node_modules/some-dependency` as a source, even though normally all files in `node_modules` are ignored. Note that you need to specify an exact directory; `{bower_components,node_modules}/**/*.js` won't work.
@@ -77,7 +77,7 @@ If your tests write to disk they may trigger the watcher to rerun your tests. Co
AVA tracks which source files your test files depend on. If you change such a dependency only the test file that depends on it will be rerun. AVA will rerun all tests if it cannot determine which test file depends on the changed source file.
Dependency tracking works for required modules. Custom extensions and transpilers are supported, provided you [added them in your `package.json`], and not from inside your test file. Files accessed using the `fs` module are not tracked.
Dependency tracking works for required modules. Custom extensions and transpilers are supported, provided you [added them in your `package.json` or `ava.config.js` file][config], and not from inside your test file. Files accessed using the `fs` module are not tracked.
## Watch mode and the `.only` modifier
@@ -118,5 +118,4 @@ Watch mode is relatively new and there might be some rough edges. Please [report
[Install Troubleshooting]: https://github.com/paulmillr/chokidar#install-troubleshooting
[`ignore-by-default`]: https://github.com/novemberborn/ignore-by-default
[`.only` modifier]: https://github.com/avajs/ava#running-specific-tests
[`ava` section of your `package.json`]: https://github.com/avajs/ava#configuration
[added them in your `package.json`]: https://github.com/avajs/ava#configuration
[config]: https://github.com/avajs/ava#configuration
View
@@ -6,8 +6,8 @@ const figures = require('figures');
const arrify = require('arrify');
const meow = require('meow');
const Promise = require('bluebird');
const pkgConf = require('pkg-conf');
const isCi = require('is-ci');
const loadConf = require('./load-config');
// Bluebird specific
Promise.longStackTraces();
@@ -18,10 +18,13 @@ function exit(message) {
}
exports.run = () => { // eslint-disable-line complexity
const conf = pkgConf.sync('ava');
const filepath = pkgConf.filepath(conf);
const projectDir = filepath === null ? process.cwd() : path.dirname(filepath);
let conf = {};
let confError = null;
try {
conf = loadConf();
} catch (err) {
confError = err;
}
const cli = meow(`
Usage
@@ -110,6 +113,15 @@ exports.run = () => { // eslint-disable-line complexity
updateNotifier({pkg: cli.pkg}).notify();
const chalk = require('./chalk').set({enabled: cli.flags.color});
if (confError) {
if (confError.parent) {
exit(`${confError.message}\n\n${chalk.gray((confError.parent && confError.parent.stack) || confError.parent)}`);
} else {
exit(confError.message);
}
}
const {projectDir} = conf;
if (cli.flags.resetCache) {
const cacheDir = path.join(projectDir, 'node_modules', '.cache', 'ava');
del('*', {
View
@@ -0,0 +1,58 @@
'use strict';
const path = require('path');
const esm = require('esm');
const isPlainObject = require('is-plain-object');
const pkgConf = require('pkg-conf');
const NO_SUCH_FILE = Symbol('no ava.config.js file');
const MISSING_DEFAULT_EXPORT = Symbol('missing default export');
function loadConfig(defaults = {}) {
const packageConf = pkgConf.sync('ava');
const filepath = pkgConf.filepath(packageConf);
const projectDir = filepath === null ? process.cwd() : path.dirname(filepath);
let fileConf;
try {
({default: fileConf = MISSING_DEFAULT_EXPORT} = esm(module, {
cjs: false,
mode: 'all'
})(path.join(projectDir, 'ava.config.js')));

This comment has been minimized.

@jdalton

jdalton Jun 1, 2018

Contributor

πŸ‘† Let me know if you have any tweaks. The cjs:false option means that named exports of cjs files are not supported out-of-the-box. You can opt-in to them with:

cjs: {
  namedExports: true
},
mode: 'all'
} catch (err) {
if (err && err.code === 'MODULE_NOT_FOUND') {
fileConf = NO_SUCH_FILE;
} else {
throw Object.assign(new Error('Error loading ava.config.js'), {parent: err});
}
}
if (fileConf === MISSING_DEFAULT_EXPORT) {
throw new Error('ava.config.js must have a default export, using ES module syntax');
}
if (fileConf !== NO_SUCH_FILE) {
if (Object.keys(packageConf).length > 0) {
throw new Error('Conflicting configuration in ava.config.js and package.json');
}
if (fileConf && typeof fileConf.then === 'function') {
throw new TypeError('ava.config.js must not export a promise');
}
if (!isPlainObject(fileConf) && typeof fileConf !== 'function') {
throw new TypeError('ava.config.js must export a plain object or factory function');
}
if (typeof fileConf === 'function') {
fileConf = fileConf({projectDir});
if (fileConf && typeof fileConf.then === 'function') {
throw new TypeError('Factory method exported by ava.config.js must not return a promise');
}
if (!isPlainObject(fileConf)) {
throw new TypeError('Factory method exported by ava.config.js must return a plain object');
}
}
}
return Object.assign({}, defaults, fileConf, packageConf, {projectDir});
}
module.exports = loadConfig;
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -91,6 +91,7 @@
"emittery": "^0.3.0",
"empower-core": "^0.6.1",
"equal-length": "^1.0.0",
"esm": "^3.0.15",
"escape-string-regexp": "^1.0.5",
"figures": "^2.0.0",
"get-port": "^3.2.0",
@@ -143,7 +144,6 @@
"codecov": "^3.0.0",
"del": "^3.0.0",
"delay": "^2.0.0",
"esm": "^3.0.15",
"execa": "^0.10.0",
"flow-bin": "^0.69.0",
"get-stream": "^3.0.0",
View
@@ -8,13 +8,13 @@ require('./lib/worker/load-chalk'); // eslint-disable-line import/no-unassigned-
const path = require('path');
const meow = require('meow');
const Promise = require('bluebird');
const pkgConf = require('pkg-conf');
const uniqueTempDir = require('unique-temp-dir');
const arrify = require('arrify');
const resolveCwd = require('resolve-cwd');
const babelPipeline = require('./lib/babel-pipeline');
const RunStatus = require('./lib/run-status');
const VerboseReporter = require('./lib/reporters/verbose');
const loadConfig = require('./lib/load-config');
function resolveModules(modules) {
return arrify(modules).map(name => {
@@ -30,18 +30,14 @@ function resolveModules(modules) {
Promise.longStackTraces();
const conf = pkgConf.sync('ava', {
defaults: {
babel: {
testOptions: {}
},
compileEnhancements: true
}
const conf = loadConfig({
babel: {
testOptions: {}
},
compileEnhancements: true
});
const filepath = pkgConf.filepath(conf);
const projectDir = filepath === null ? process.cwd() : path.dirname(filepath);
const {projectDir} = conf;
// Define a minimal set of options from the main CLI
const cli = meow(`
Usage
View
@@ -232,7 +232,7 @@ AVA automatically removes unrelated lines in stack traces, allowing you to find
## Configuration
All of the CLI options can be configured in the `ava` section of your `package.json`. This allows you to modify the default behavior of the `ava` command, so you don't have to repeatedly type the same options on the command prompt.
All of the CLI options can be configured in the `ava` section of either your `package.json` or an `ava.config.js` file. This allows you to modify the default behavior of the `ava` command, so you don't have to repeatedly type the same options on the command prompt.
To ignore a file or directory, prefix the pattern with an `!` (exclamation mark).
@@ -291,6 +291,47 @@ Arguments passed to the CLI will always take precedence over the configuration i
Note that providing files on the CLI overrides the `files` option. If you've configured a glob pattern, for instance `test/**/*.test.js`, you may want to repeat it when using the CLI: `ava 'test/integration/*.test.js'`.
### Using `ava.config.js`
To use an `ava.config.js` file:
1. It must be in the same directory as your `package.json`
2. Your `package.json` must not contain an `ava` property (or, if it does, it must be an empty object)
The config file must have a default export, using ES modules. It can either be a plain object or a factory function which returns a plain object:
```js
export default {
require: ['esm']
};
```
```js
export default function factory() {
return {
require: ['esm']
};
};
```
The factory function is called with an object containing a `projectDir` property, which you could use to change the returned configuration:
```js
export default ({projectDir}) => {
if (projectDir === '/Users/username/projects/my-project') {
return {
// Config A
};
}
return {
// Config B
};
};
```
Note that the final configuration must not be a promise.
## Documentation
Tests are run concurrently. You can specify synchronous and asynchronous tests. Tests are considered synchronous unless you return a promise or [observable](https://github.com/zenparsing/zen-observable).
View
@@ -121,6 +121,20 @@ for (const [where, which, msg = '\'js\', \'jsx\''] of [
});
}
test('formats errors from ava.config.js', t => {
execCli(['es2015.js'], {dirname: 'fixture/load-config/throws'}, (err, stdout, stderr) => {
t.ok(err);
const lines = stderr.split('\n');
t.is(lines[0], '');
t.is(lines[1], figures.cross + ' Error loading ava.config.js');
t.is(lines[2], '');
t.match(lines[3], /ava\.config\.js/);
t.match(lines[4], /foo/);
t.end();
});
});
test('enabling long stack traces will provide detailed debug information', t => {
execCli('fixture/long-stack-trace', (err, stdout, stderr) => {
t.ok(err);
@@ -0,0 +1,3 @@
class Config {}
export default () => new Config();
@@ -0,0 +1,5 @@
export default () => new Promise(resolve => {
resolve({
files: 'this-should-not-work'
});
});
@@ -0,0 +1 @@
export const config = {}; // eslint-disable-line import/prefer-default-export
@@ -0,0 +1 @@
export default 'should not work!';
@@ -0,0 +1 @@
export default Promise.resolve('should not work!');
@@ -0,0 +1,5 @@
export default ({projectDir}) => {
return {
files: projectDir
};
};
@@ -0,0 +1,5 @@
const config = {
files: 'config-file-esm-test-value'
};
export default config;
@@ -0,0 +1,6 @@
{
"ava": {
"failFast": true,
"concurrency": 10
}
}
@@ -0,0 +1,3 @@
export default {
files: 'package-yes-files-yes-test-value'
};
@@ -0,0 +1,8 @@
{
"ava": {
"files": [
"abc",
"!xyz"
]
}
}
@@ -0,0 +1 @@
throw new Error('foo');
@@ -0,0 +1 @@
{}
Oops, something went wrong.

0 comments on commit 16f4742

Please sign in to comment.