Skip to content
Permalink
Browse files

Groundwork to support experimental features

From time to time, AVA will implement experimental features. These may
change or be removed at any time, not just when there's a new major
version. You can opt-in to such a feature by enabling it in the
`nonSemVerExperiments` configuration.
  • Loading branch information...
novemberborn committed Aug 18, 2019
1 parent 0a5c933 commit 03c15093772b413ac343cb1c3940338b6dfc4b20
@@ -162,4 +162,19 @@ test('My test', t => {

AVA has a minimum depth of `3`.

## Experiments

From time to time, AVA will implement experimental features. These may change or be removed at any time, not just when there's a new major version. You can opt-in to such a feature by enabling it in the `nonSemVerExperiments` configuration.

`ava.config.js`:
```js
export default {
nonSemVerExperiments: {
feature: true
}
};
```

There are currently no such features available.

[CLI]: ./05-command-line.md
@@ -15,3 +15,5 @@ We try to avoid *accidentally* dropping support for non-latest Node.js releases.
We may explicitly drop support for non-latest Node.js releases. If this occurs we will bump AVA's major version number. This may be due to adoption of backported APIs or the availability of newer V8 releases in later Node.js versions, either in AVA itself or one of our dependencies.

We may drop support for a Node.js version, in a major-version-bumping-pre-release, if that new AVA version is expected to become stable around or after the end-of-life date of the Node.js version in question.

Experimental features opted into through the `nonSemVerExperiments` configuration may be changed or removed at any time.
@@ -149,6 +149,7 @@ class Api extends Emittery {

await this.emit('run', {
clearLogOnNextRun: runtimeOptions.clearLogOnNextRun === true,
experiments: Object.keys(apiOptions.experiments),
failFastEnabled: failFast,
filePathPrefix: commonPathPrefix(files),
files,
@@ -238,6 +238,7 @@ exports.run = async () => { // eslint-disable-line complexity
color: conf.color,
compileEnhancements: conf.compileEnhancements !== false,
concurrency: conf.concurrency ? parseInt(conf.concurrency, 10) : 0,
experiments: conf.nonSemVerExperiments,
extensions,
failFast: conf.failFast,
failWithoutAssertions: conf.failWithoutAssertions !== false,
@@ -6,6 +6,7 @@ const pkgConf = require('pkg-conf');

const NO_SUCH_FILE = Symbol('no ava.config.js file');
const MISSING_DEFAULT_EXPORT = Symbol('missing default export');
const EXPERIMENTS = new Set([]);

function loadConfig({configFile, resolveFrom = process.cwd(), defaults = {}} = {}) { // eslint-disable-line complexity
let packageConf = pkgConf.sync('ava', {cwd: resolveFrom});
@@ -82,7 +83,20 @@ function loadConfig({configFile, resolveFrom = process.cwd(), defaults = {}} = {
}
}

return {...defaults, ...fileConf, ...packageConf, projectDir};
const config = {...defaults, nonSemVerExperiments: {}, ...fileConf, ...packageConf, projectDir};

const {nonSemVerExperiments: experiments} = config;
if (!isPlainObject(experiments)) {
throw new Error(`nonSemVerExperiments from ${fileForErrorMessage} must be an object`);
}

for (const key of Object.keys(experiments)) {
if (!EXPERIMENTS.has(key)) {
throw new Error(`nonSemVerExperiments.${key} from ${fileForErrorMessage} is not a supported experiment`);
}
}

return config;
}

module.exports = loadConfig;
@@ -135,6 +135,11 @@ class MiniReporter {

cliCursor.hide(this.reportStream);
this.lineWriter.writeLine();

if (plan.experiments.length > 0) {
this.lineWriter.writeLine(colors.information(`${figures.warning} Experiments are enabled. These are unsupported and may change or be be removed at any time.`));
}

this.spinner.start();
}

@@ -97,6 +97,9 @@ class VerboseReporter {
}

this.lineWriter.writeLine();
if (plan.experiments.length > 0) {
this.lineWriter.writeLine(colors.information(`${figures.warning} Experiments are enabled. These are unsupported and may change or be removed at any time.${os.EOL}`));
}
}

consumeStateChange(evt) { // eslint-disable-line complexity
@@ -145,6 +145,7 @@ runStatus.observeWorker({
}, file);

reporter.startRun({
experiments: [],
failFastEnabled: false,
files: [file],
matching: false,
@@ -32,6 +32,7 @@ function apiCreator(options = {}) {
options.babelConfig = babelPipeline.validate(options.babelConfig);
options.concurrency = 2;
options.extensions = options.extensions || {all: ['js'], enhancementsOnly: [], full: ['js']};
options.experiments = {};
options.globs = normalizeGlobs(options.files, options.helpers, options.sources, options.extensions.all);
options.projectDir = options.projectDir || ROOT_DIR;
options.resolveTestsFrom = options.resolveTestsFrom || options.projectDir;
@@ -0,0 +1,3 @@
export default {
nonSemVerExperiments: []
};
@@ -0,0 +1 @@
{}
@@ -0,0 +1,5 @@
export default {
nonSemVerExperiments: {
unsupported: true
}
};
@@ -0,0 +1 @@
{}
@@ -80,6 +80,7 @@ const run = (type, reporter, match = []) => {
require: [],
cacheEnabled: true,
compileEnhancements: true,
experiments: {},
match,
babelConfig: {testOptions: {}},
resolveTestsFrom: projectDir,
@@ -131,3 +131,15 @@ test('throws an error if a config file contains `ava` property', t => {
t.throws(loadConfig, /Encountered 'ava' property in ava.config.js; avoid wrapping the configuration/);
t.end();
});

test('throws an error if a config file contains a non-object `nonSemVerExperiments` property', t => {
changeDir('non-object-experiments');
t.throws(loadConfig, /nonSemVerExperiments from ava.config.js must be an object/);
t.end();
});

test('throws an error if a config file enables an unsupported experiment', t => {
changeDir('unsupported-experiments');
t.throws(loadConfig, /nonSemVerExperiments.unsupported from ava.config.js is not a supported experiment/);
t.end();
});

0 comments on commit 03c1509

Please sign in to comment.
You can’t perform that action at this time.