Security News
ESLint is Now Language-Agnostic: Linting JSON, Markdown, and Beyond
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
AVA is a test runner for Node.js with a concise API, detailed error output, and process isolation that allows for fast and reliable testing. It supports asynchronous testing, and its design encourages writing tests that run concurrently.
Concurrent Test Execution
AVA runs tests concurrently, which can lead to faster test execution. The example shows two tests, one synchronous and one asynchronous, both of which will run concurrently.
const test = require('ava');
test('foo', t => {
t.pass();
});
test('bar', async t => {
const bar = Promise.resolve('bar');
t.is(await bar, 'bar');
});
Snapshot Testing
AVA supports snapshot testing, which allows you to save the output of your tests and compare it to future test runs. This is useful for ensuring that your code's output remains consistent over time.
const test = require('ava');
test('snapshot', t => {
const obj = {foo: 'bar'};
t.snapshot(obj);
});
Power Assert
AVA uses power-assert to provide detailed assertion messages, making it easier to understand why a test failed. The example shows a failing test with a clear assertion message.
const test = require('ava');
test('power assert', t => {
const x = 'foo';
t.is(x, 'bar');
});
Test Isolation
AVA ensures that each test runs in isolation, preventing side effects from affecting other tests. The example shows how `t.context` can be used to set up data for each test.
const test = require('ava');
test.beforeEach(t => {
t.context.data = {foo: 'bar'};
});
test('test 1', t => {
t.context.data.foo = 'baz';
t.is(t.context.data.foo, 'baz');
});
test('test 2', t => {
t.is(t.context.data.foo, 'bar');
});
Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. It provides a variety of interfaces (e.g., BDD, TDD) and supports both synchronous and asynchronous testing. Compared to AVA, Mocha is more flexible but requires more configuration to achieve similar functionality.
Jest is a delightful JavaScript Testing Framework with a focus on simplicity. It works out of the box for most JavaScript projects and includes features like snapshot testing, a built-in mocking library, and code coverage. Jest is more opinionated than AVA and provides a more integrated experience, especially for React applications.
Tape is a tap-producing test harness for Node.js and browsers. It is minimalistic and focuses on providing a simple API for writing tests. Tape does not include features like test runners or reporters, which makes it less feature-rich compared to AVA but also simpler and more lightweight.
Futuristic test runner
Even though JavaScript is single-threaded, IO in Node.js can happen in parallel due to its async nature. AVA takes advantage of this and runs your tests concurrently, which is especially beneficial for IO heavy tests. In addition, test files are run in parallel as separate processes, giving you even better performance and an isolated environment for each test file. Switching from Mocha to AVA in Pageres brought the test time down from 31 sec to 11 sec. Having tests run concurrently forces you to write atomic tests, meaning tests don't depend on global state or the state of other tests, which is a great thing!
import test from 'ava';
test(t => {
t.same([1, 2], [1, 2]);
t.end();
});
Install AVA globally $ npm install --global ava
and run $ ava --init
(with any options) to add AVA to your package.json or create one.
{
"name": "awesome-package",
"scripts": {
"test": "ava"
},
"devDependencies": {
"ava": "^0.3.0"
}
}
import test from 'ava';
test('foo', t => {
t.pass();
t.end();
});
test('bar', t => {
t.plan(2);
setTimeout(() => {
t.is('bar', 'bar');
t.same(['a', 'b'], ['a', 'b']);
}, 100);
});
$ npm test
$ ava --help
Usage
ava [<file|folder|glob> ...]
Options
--init Add AVA to your project
--fail-fast Stop after first test failure
--serial Run tests serially
Examples
ava
ava test.js test2.js
ava test-*.js
ava --init
ava --init foo.js
Default patterns when no arguments:
test.js test-*.js test/*.js
Files starting with _
are ignored. This can be useful for having helpers in the same directory as your test files.
Tests are run asynchronously and require you to either set planned assertions t.plan(1)
, explicitly end the test when done t.end()
, or return a promise. Async functions already returns a promise implicitly, so no need for you to explicitly return a promise in that case.
You have to define all tests synchronously, meaning you can't define a test in the next tick, e.g. inside a setTimeout
.
Test files are run from their current directory, so process.cwd()
is always the same as __dirname
. You can just use relative paths instead of doing path.join(__dirname, 'relative/path')
.
To create a test, you call the test
function you require
d from AVA and pass in an optional test name and a function containing the test execution. The passed function is given the context as the first argument, where you can call the different AVA methods and assertions.
test('name', t => {
t.pass();
t.end();
});
Naming a test is optional, but you're recommended to use one if you have more than one test.
test(t => {
t.end();
});
You can also choose to use a named function instead:
test(function name(t) {
t.end();
});
Planned assertions are useful for being able to assert that all async actions happened. It also comes with the benefit of not having to manually end the test.
This will result in a passed test:
test(t => {
t.plan(1);
setTimeout(() => {
t.pass();
}, 100);
});
While concurrency is awesome, there are some things that can't be done concurrently. In these rare cases, you can call test.serial
, which will force those tests to run serially before the concurrent ones.
test.serial(t => {
t.end();
});
Only-tests enforces only those tests to be run. This can be useful for running only a few tests during development.
test('will not be run', t => {
t.fail();
t.end();
})
test.only('will be run', t => {
t.pass();
t.end();
});
Skip-tests are shown in the output as skipped but never run.
test.skip('unicorn', t => {
t.end();
});
When setup and/or teardown is required, you can use test.before()
and test.after()
,
used in the same manner as test()
. The test function given to test.before()
and test.after()
is called before/after all tests. You can also use test.beforeEach()
and test.afterEach()
if you need setup/teardown for each test. Hooks are run serially in the test file. Add as many of these as you want. You can optionally specify a title that is shown on failure.
test.before(t => {
// this runs before all tests
t.end();
});
test.before(t => {
// this runs after the above, but before tests
t.end();
});
test.after('cleanup', t => {
// this runs after all tests
t.end();
});
test.beforeEach(t => {
// this runs before each test
t.end();
});
test.afterEach(t => {
// this runs after each test
t.end();
});
test(t => {
// regular test
t.end();
});
The beforeEach
& afterEach
hooks can share context with the test:
test.beforeEach(t => {
t.context.data = generateUniqueData();
t.end();
});
test(t => {
t.is(t.context.data + 'bar', 'foobar');
t.end();
});
The context is by default an object, but it can also be directly assigned:
test.beforeEach(t => {
t.context = 'unicorn';
t.end();
});
test(t => {
t.is(t.context, 'unicorn');
t.end();
});
You can use any assertion module instead or in addition to the one that comes with AVA, but you won't be able to use the .plan()
method, yet.
import assert from 'assert';
test(t => {
assert(true);
t.end();
});
AVA comes with builtin support for ES2015 through Babel.
Just write your tests in ES2015. No extra setup needed.
test(t => {
t.pass();
t.end();
});
You can also use your own local Babel version:
{
"devDependencies": {
"ava": "^0.3.0",
"babel-core": "^5.8.0"
}
}
If you return a promise in the test you don't need to explicitly end the test as it will end when the promise resolves.
test(t => {
return somePromise().then(result => {
t.is(result, 'unicorn');
});
});
AVA comes with builtin support for generator functions.
test(function * (t) {
const value = yield generatorFn();
t.true(value);
});
You don't have to manually call t.end()
.
AVA comes with builtin support for async functions (async/await).
test(async function (t) {
const value = await promiseFn();
t.true(value);
});
// async arrow function
test(async t => {
const value = await promiseFn();
t.true(value);
});
You don't have to manually call t.end()
.
AVA comes with builtin support for observables.
test(t => {
return Observable.of(1, 2, 3).map(n => {
t.true(n > 0);
return n * n;
});
});
You don't have to manually call t.end()
.
AVA supports using t.end
as the final callback when using node-style
error-first callback APIs. AVA will consider any truthy value passed as
the first argument to t.end
to be an error.
test(t => {
// t.end automatically checks for error as first argument
fs.readFile('data.txt', t.end);
});
Type: string
Test title.
Type: function
Should contain the actual test.
Passed into the test function and contains the different AVA methods and assertions.
Plan how many assertion there are in the test. The test will fail if the actual assertion count doesn't match planned assertions. When planned assertions are used you don't need to explicitly end the test.
Be aware that this doesn't work with custom assert modules. You must then call .end()
explicitly.
End the test. Use this when plan()
is not used.
Assertions are mixed into the test context:
test(t => {
t.ok('unicorn'); // assertion
t.end();
});
If multiple assertion failures are encountered within a single test, AVA will only display the first one.
Passing assertion.
Failing assertion.
Assert that value
is truthy.
Assert that value
is falsy.
Assert that value
is true
.
Assert that value
is false
.
Assert that value
is equal to expected
.
Assert that value
is not equal to expected
.
Assert that value
is deep equal to expected
.
Assert that value
is not deep equal to expected
.
Assert that function
throws an error or promise
rejects.
error
can be a constructor, regex, error message or validation function.
Assert that function
doesn't throw an error
or promise
resolves.
Assert that regex
matches contents
.
Assert that error
is falsy.
AVA comes with power-assert
builtin, giving you more descriptive assertion messages. It reads your test and tries to infer more information from the code.
The following test:
test(t => {
const x = 'foo';
t.ok(x === 'bar');
t.end();
});
Would normally give the unhelpful output:
false === true
With the enhanced asserts, you'll get:
t.ok(x === 'bar')
|
"foo"
True, you could use t.is()
in this case, and probably should, but this is just a simple example.
Let try a more advanced example:
test(t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.ok(a.test(b) || b === c);
t.end();
});
And there you go:
t.ok(a.test(b) || b === c)
| | | |
| "bar" "bar" "baz"
false
All the assert methods are enhanced.
Have fun!
Each test file is run in a separate Node.js process. This comes with a lot of benefits. Different test files can no longer affect each other. Like test files mocking with the global environment, overriding builtins, etc. However, it's mainly done for performance reasons. Even though Node.js can run async IO concurrently, that doesn't help much when tests are heavy on synchronous operations, which blocks the main thread. By running tests concurrently and test files in parallel we take full advantage of modern systems.
Running tests concurrently comes with some challenges, doing IO is one. Usually, serial tests just create temp directories in the current test directory and cleans it up at the end. This won't work when you run tests concurrently as tests will conflict with each other. The correct way to do it is to use a new temp directory for each test. The tempfile
and temp-write
modules can be helpful.
AVA runs tests concurrently by default, which is suboptimal when you need to debug something. Instead, run tests serially with the --serial
option:
$ ava --serial
You can't use istanbul
for code coverage as AVA spawns the test files, but you can use nyc
instead, which is basically istanbul
with support for subprocesses.
mocha
, tape
, node-tap
?Mocha requires you to use implicit globals like describe
and it
with the default interface (which most people use), too unopinionated, bloated, synchronous by default, serial test execution, and slow. Tape and node-tap are pretty good. AVA is highly inspired by their syntax. However, they both execute tests serially and they've made TAP a first-class citizen which has IMHO made their codebases a bit convoluted and coupled. TAP output is hard to read so you always end up using an external tap reporter. AVA is highly opinionated and concurrent. It comes with a default simple reporter and will in the future support TAP through a reporter.
AVA, not Ava or ava. Pronounced /ˈeɪvə/
ay-və.
Concurrency is not parallelism. It enables parallelism. Learn more.
Sindre Sorhus | Kevin Mårtensson | Vadim Demedes | James Talmage |
FAQs
Node.js test runner that lets you develop with confidence.
The npm package ava receives a total of 240,156 weekly downloads. As such, ava popularity was classified as popular.
We found that ava demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
ESLint has added JSON and Markdown linting support with new officially-supported plugins, expanding its versatility beyond JavaScript.
Security News
Members Hub is conducting large-scale campaigns to artificially boost Discord server metrics, undermining community trust and platform integrity.
Security News
NIST has failed to meet its self-imposed deadline of clearing the NVD's backlog by the end of the fiscal year. Meanwhile, CVE's awaiting analysis have increased by 33% since June.