Translations: Français
Until 1.4.1 AVA came bundled with a Flow definition file. This allows developers to leverage Flow for writing tests.
We need some help publishing the type definitions outside of AVA. Please join us in avajs/flow-typed#1 if you'd like to help out.
This guide assumes you've already set up Flow for your project. Note that AVA's definition as been tested with version 0.95.1.
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
and customize AVA's configuration in the package.json
file (or the ava.config.js
file) as follows.
package.json
:
{
"ava": {
"babel": {
"testOptions": {
"plugins": [
"@babel/plugin-transform-flow-strip-types"
]
}
}
}
}
See our Babel documentation for more details.
Create a test.js
file.
// @flow
import test from 'ava';
const getFoo = () => 'foo';
test('check getFoo', t => {
t.is(getFoo(), 'foo');
});
Typing t.context
By default, the type of t.context
will be the empty object ({}
). AVA exposes an interface TestInterface<Context>
which you can use to apply your own type to t.context
. This can help you catch errors at compile-time:
// @flow
import anyTest from 'ava';
import type {TestInterface} from 'ava';
const test: TestInterface<{foo: string}> = (anyTest: any);
test.beforeEach(t => {
t.context = {foo: 'bar'};
});
test.beforeEach(t => {
t.context.foo = 123; // error: Type '123' is not assignable to type 'string'
});
test.serial.cb.failing('very long chains are properly typed', t => {
t.context.fooo = 'a value'; // error: Property 'fooo' does not exist on type ''
});
test('an actual test', t => {
t.deepEqual(t.context.foo.map(c => c), ['b', 'a', 'r']); // error: Property 'map' does not exist on type 'string'
});
Note that, despite the type cast above, when executing t.context
is an empty object unless it's assigned.
The t.throws()
and t.throwsAsync()
assertions are typed to always return an Error. You can customize the error class using generics:
// @flow
import test from 'ava';
class CustomError extends Error {
parent: Error;
constructor(parent) {
super(parent.message);
this.parent = parent;
}
}
function myFunc() {
throw new CustomError(new TypeError('🙈'));
};
test('throws', t => {
const err = t.throws<CustomError>(myFunc);
t.is(err.parent.name, 'TypeError');
});
test('throwsAsync', async t => {
const err = await t.throwsAsync<CustomError>(async () => myFunc());
t.is(err.parent.name, 'TypeError');
});
Note that, despite the typing, the assertion returns undefined
if it fails. Typing the assertions as returning Error | undefined
didn't seem like the pragmatic choice.