Skip to content

Commit 4175186

Browse files
committed
Refactor Flowtype definition
Minor syntactical changes aside, it's now equivalent to the TypeScript definition!
1 parent 927f535 commit 4175186

File tree

9 files changed

+322
-194
lines changed

9 files changed

+322
-194
lines changed

docs/recipes/flow.md

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Flow
2+
3+
AVA comes bundled with a Flow definition file. This allows developers to leverage Flow for writing tests.
4+
5+
This guide assumes you've already set up Flow for your project. Note that AVA's definition as been tested with version 0.64.
6+
7+
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:
8+
9+
```json
10+
{
11+
"ava": {
12+
"babel": {
13+
"testOptions": {
14+
"plugins": ["@babel/plugin-transform-flow-strip-types"]
15+
}
16+
}
17+
}
18+
}
19+
```
20+
21+
See our [Babel documentation](babel.md) for more details.
22+
23+
## Writing tests
24+
25+
Create a `test.js` file.
26+
27+
```js
28+
// @flow
29+
import test from 'ava';
30+
31+
const fn = async () => Promise.resolve('foo');
32+
33+
test(async (t) => {
34+
t.is(await fn(), 'foo');
35+
});
36+
```
37+
38+
## Typing [`t.context`](https://github.com/avajs/ava#test-context)
39+
40+
By default, the type of `t.context` will be [`any`](https://www.typescriptlang.org/docs/handbook/basic-types.html#any). 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:
41+
42+
```js
43+
// @flow
44+
import anyTest, {TestInterface} from 'ava';
45+
import type {TestInterface} from 'ava';
46+
47+
const test: TestInterface<{foo: string}> = anyTest;
48+
49+
test.beforeEach(t => {
50+
t.context = {foo: 'bar'};
51+
});
52+
53+
test.beforeEach(t => {
54+
t.context.foo = 123; // error: Type '123' is not assignable to type 'string'
55+
});
56+
57+
test.serial.cb.failing('very long chains are properly typed', t => {
58+
t.context.fooo = 'a value'; // error: Property 'fooo' does not exist on type ''
59+
});
60+
61+
test('an actual test', t => {
62+
t.deepEqual(t.context.foo.map(c => c), ['b', 'a', 'r']); // error: Property 'map' does not exist on type 'string'
63+
});
64+
```
65+
66+
Note that `t.context` is `null` unless it's assigned. You'll have to guard against this to avoid Flow errors:
67+
68+
```ts
69+
import anyTest, {TestInterface} from 'ava';
70+
71+
const test: TestInterface<{foo: string}> = anyTest;
72+
73+
test.beforeEach(t => {
74+
t.context = {foo: 'bar'};
75+
});
76+
77+
test('foo is bar', t => {
78+
t.context && t.is(t.context.foo, 'bar');
79+
});
80+
```
81+
82+
## Using `t.throws()` and `t.notThrows()`
83+
84+
The `t.throws()` and `t.noThrows()` assertions can be called with a function that returns an observable or a promise. You may have to explicitly type functions:
85+
86+
```ts
87+
import test from 'ava';
88+
89+
test('just throws', async t => {
90+
const expected = new Error();
91+
const err = t.throws((): void => { throw expected; });
92+
t.is(err, expected);
93+
94+
const err2 = await t.throws((): Promise<*> => Promise.reject(expected));
95+
t.is(err2, expected);
96+
});
97+
```

0 commit comments

Comments
 (0)