AVA Tutorial
posted in javascript on • by Wouter Van Schandevijlavajs/ava : 🚀 Testing can be a drag. AVA helps you get it done.
A concurrent test runner from the Andromeda galaxy. If I was to stray from
Jasmine then it could only
be for a project Sindre Sorhus is working on :)
The screenshots on the project site promised extensive assertion failure output with clean stack traces
and built-in Promise, async/await, Observable and React component support.
So I tried it out and yup, AVA delivered.
Get Started
# Install
npm init ava
# Run tests
npx ava --watch --verbose
AVA runs automatically ignore:
- Directories called
fixtures
,helpers
ornode_modules
- Files starting with an underscore (
_
)
Checkout the recipes for examples when working with TypeScript, Flow, Babel, React, Vue.js, Debugging with Chrome DevTools and WebStorm and much more… There is also a Common Pitfalls document should you run into some trouble early on.
Example
import test from 'ava';
// Parameter needs to be called `t`
// for enhanced assertion messages.
test('Basic test example', t => {
// Test will fail if not exactly
// two assertions are made
t.plan(2);
t.pass();
// Skipped tests still count to the plan
t.true.skip();
t.log(...values);
// Test fails if exceeded.
// Resets after each assertion.
// There is no default timeout.
// Globally from CLI: --timeout=10s
t.timeout(ms);
});
// HOOKS:
// Runs before the first test in the file
// Runs before beforeEach hooks, if any.
test.before('optional title', t => {
t.context.data = 'Shared with the tests';
// t.context is an object by default but may be overwritten
});
// Runs after the last test in the file
test.after(() => {});
// Individual test setup/teardown
test.beforeEach(() => {});
test.afterEach(() => {});
// Will run even if other hooks or the test fails
test.afterEach.always(() => {});
// Also: test.after.always()
// Hooks run concurrently by default, unless:
test.serial.before(() => {});
Assertions
You can use any assertion library instead of or in addition to the built-in one, provided it throws exceptions on failures.
All built-in assertions have a last optional message
parameter.
import test from 'ava';
test('Built-in', t => {
t.pass('optional message');
t.fail();
t.true(value); // t.false()
t.truthy(value); // t.falsy()
t.is(value, expected); // Object.is() comparison
t.not(value, expected); // Inverted t.is()
t.regex(contents, regex); // Also: notRegex()
t.deepEqual(value, expected); // Also: notDeepEqual()
});
power-assert
power-assert-js/power-assert : Very fancy assertion failure reporting
// Outputs failures with power-assert when value is falsy
t.assert(value, [message]);
Macros
Create custom testers with macros.
function macro(t, input, expected) {
t.is(input, expected);
}
test('static title', macro, 'input', 'expected');
// Dynamic Titles
macro.title = (providedTitle = undefined, input, expected) => '';
test(macro, 'input', 'expected');
test('providedTitle', macro, 'in', 'expected');
Exceptions
test('throws error', t => {
const err = t.throws(fn, [expected]); // Also: .notThrows()
// with expected either
// - A constructor (instanceof)
// - A string (error.message comparison)
// - A RegExp (error.message match)
// - A matcher object. Ex:
const matcher = {
instanceOf: TypeError,
is: 'Object.is()',
message: 'string | RegExp',
name: 'err.name',
code: 'err.code',
};
// When omitting expected, you still need to
// pass null if you want to set the message.
});
test('throws async', async t => {
await t.throwsAsync(async () => {
throw new TypeError('oops');
}, {instanceOf: TypeError, message: 'oops'});
// Also: .notThrowsAsync()
const error = await t.throwsAsync(() => Promise.reject('aargh'));
t.is(error.message, 'aargh');
});
Not included
- Endpoint testing Recipe: Use your favourite library
- Browser testing
- Anything else you might need? Someone might have done it already: Awesome AVA
Workflow
test.only('Like Jasmine fit', t => {
t.pass();
});
test.skip('Like Jasmine xit', t => {
t.pass();
});
test.todo('Really need to write this test');
test.failing('Passes only when the test does NOT pass', t => {
t.fail();
});
CLI
Always runs the local AVA installation if available.
CLI takes precedence over configuration.
npx ava --help
# Default arguments
npx ava test.js test-*.js test/**/*.js **/__tests__/**/*.js **/*.test.js
npx ava
--watch # or -w
--verbose # or -v: Outputs all test titles
--match # or -m: Run only matching test titles
--timeout # or -T: in ms. Or: "30s" (30 seconds), "3m" (3 minutes)
--fail-fast # Stop on first failure
# Case insensitive test title matching
# Overrides .only
npx ava -m='startWith*' -m='!*notContains*' -m='exact'
sindresorhus/matcher
:
Matcher used for --match
Other CLI parameters
--serial
,-s
: Run tests serially--concurrency
,-c
: Max tests running at the same time (Default: # CPU Cores)--tap
,-t
: Generate Test Anything Protocol output--color
and--no-color
: With color by default--reset-cache
Configuration
In your package.json
:
{
"ava": {
"files": [
"my-test-directory/**/*.js",
"!my-test-directory/exclude-this-directory/**/*.js",
"!**/exclude-this-file.js"
],
"sources": [ // changes to matching files re-run tests while in --watch mode
"**/*.{js,jsx}",
"!dist/**/*"
],
"failWithoutAssertions": false, // True by default: a test without assertion fails
"compileEnhancements": false, // Disable power-assert
"require": [
"@babel/register"
],
"babel": {
"extensions": ["jsx"],
"testOptions": {
"babelrc": false
}
},
"a-cli-arg": "ex: 'failFast': true"
}
}
- Can also add json nodes matching the CLI parameters for failFast, tap, verbose, timeout and
match: string[]
cache
:true
: Use cache innode_modules/.cache/ava
.false
: Use temp dir.- Also possible to create a
ava.config.js
in the same folder as yourpackage.json
.
Async Support
test('Promise support', t => {
return Promise.resolve(true).then(result => {
t.true(result);
});
});
test('async/await support', async t => {
const value = await Promise.resolve(true);
t.true(value);
});
test('Observable support', t => {
return of(1).pipe(map(() => t.pass()));
});
test.cb('Callback support with t.end', t => {
// Any truthy value passed as first argument
// to `t.end` will fail the test
fs.readFile('data.txt', t.end);
});
test.afterEach.cb('This stuff also works for hooks', t => {
setImmediate(t.end);
});
console.log('Currently running', test.meta.file);
- avajs/awesome-ava : Awesome AVA