Skip to content

Commit 982a451

Browse files
committed
update documentation to reflect new behaviors
1 parent f816815 commit 982a451

File tree

1 file changed

+91
-45
lines changed

1 file changed

+91
-45
lines changed

readme.md

Lines changed: 91 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,18 @@ Install AVA globally `$ npm install --global ava` and run `$ ava --init` (with a
6767

6868
```js
6969
import test from 'ava';
70+
import delay from 'delay';
7071

7172
test('foo', t => {
7273
t.pass();
73-
t.end();
7474
});
7575

76-
test('bar', t => {
77-
t.plan(2);
76+
const bar = Promise.resolve('bar').then(delay(200));
7877

79-
setTimeout(() => {
80-
t.is('bar', 'bar');
81-
t.same(['a', 'b'], ['a', 'b']);
82-
}, 100);
78+
test('bar', async t => {
79+
t.plan(2);
80+
81+
t.is(await bar, 'bar');
8382
});
8483
```
8584

@@ -121,9 +120,13 @@ Files starting with `_` are ignored. This can be useful for having helpers in th
121120

122121
## Documentation
123122

124-
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](#async-function-support) already returns a promise implicitly, so no need for you to explicitly return a promise in that case.
123+
Tests are run asynchronously and require you to return a supported async object (a promise, or [observable](https://github.com/zenparsing/zen-observable)). We *highly* recommend the use of [async functions](#async-function-support); They make async code concise and readable, and they implicitly return a promise, so you don't need to.
125124

126-
You have to define all tests synchronously, meaning you can't define a test in the next tick, e.g. inside a `setTimeout`.
125+
If you do not return one of the supported async objects mentioned above, the test is considered to be synchronous and ended immediately.
126+
127+
If you are unable to use promises or other supported async objects, you may enable legacy async support by defining your test with `test.async([title', fn)`. Tests declared this way **must** be manually ended with `t.end()`.
128+
129+
You must define all tests synchronously. They can't be defined inside `setTimeout`, `setImmediate`, etc.
127130

128131
Test files are run from their current directory, so [`process.cwd()`](https://nodejs.org/api/process.html#process_process_cwd) is always the same as [`__dirname`](https://nodejs.org/api/globals.html#globals_dirname). You can just use relative paths instead of doing `path.join(__dirname, 'relative/path')`.
129132

@@ -134,7 +137,6 @@ To create a test, you call the `test` function you `require`d from AVA and pass
134137
```js
135138
test('name', t => {
136139
t.pass();
137-
t.end();
138140
});
139141
```
140142

@@ -144,41 +146,86 @@ Naming a test is optional, but you're recommended to use one if you have more th
144146

145147
```js
146148
test(t => {
147-
t.end();
149+
t.pass();
148150
});
149151
```
150152

151153
You can also choose to use a named function instead:
152154

153155
```js
154156
test(function name(t) {
155-
t.end();
157+
t.pass();
156158
});
157159
```
158160

159-
### Planned assertions
161+
### Assertion plan
160162

161-
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.
163+
An assertion plan can be used to ensure a specific number of assertions are made.
164+
In the most common scenario, it validates that the test did not exit before executing the expected number of assertions.
165+
It also fails the test if too many assertions are executed (Useful if you have assertions inside callbacks or loops).
162166

163167
This will result in a passed test:
164168

165169
```js
166170
test(t => {
167171
t.plan(1);
168172

173+
return Promise.resolve(3).then(n => {
174+
t.is(n, 3);
175+
});
176+
});
177+
178+
test.async(t => {
169179
setTimeout(() => {
170180
t.pass();
181+
t.end();
171182
}, 100);
172183
});
173184
```
174185

186+
#### WARNING: Recent breaking change.
187+
188+
AVA no longer supports automatically ending tests via `t.plan(...)`.
189+
This helps prevent false positives if you add assertions, but forget to increase your plan count.
190+
191+
```js
192+
// This no longer works
193+
194+
test('auto ending is dangerous', t => {
195+
t.plan(2);
196+
197+
t.pass();
198+
t.pass();
199+
200+
// auto-ending after reaching the planned two assertions will miss this final one
201+
setTimeout(() => t.fail(), 10000);
202+
});
203+
```
204+
205+
For this to work, you now must use the legacy `async` test mode, and explicitly call `t.end()`.
206+
207+
```js
208+
test('explicitly end your tests', t => {
209+
t.plan(2);
210+
211+
t.pass();
212+
t.pass();
213+
214+
setTimeout(() => {
215+
// This failure is now reliably caught.
216+
t.fail();
217+
t.end();
218+
}, 1000);
219+
});
220+
```
221+
175222
### Serial-tests
176223

177224
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.
178225

179226
```js
180227
test.serial(t => {
181-
t.end();
228+
t.pass();
182229
});
183230
```
184231

@@ -189,12 +236,10 @@ Only-tests enforces only those tests to be run. This can be useful for running o
189236
```js
190237
test('will not be run', t => {
191238
t.fail();
192-
t.end();
193239
})
194240

195241
test.only('will be run', t => {
196242
t.pass();
197-
t.end();
198243
});
199244
```
200245

@@ -203,8 +248,8 @@ test.only('will be run', t => {
203248
Skip-tests are shown in the output as skipped but never run.
204249

205250
```js
206-
test.skip('unicorn', t => {
207-
t.end();
251+
test.skip('will not be run', t => {
252+
t.fail();
208253
});
209254
```
210255

@@ -217,32 +262,42 @@ used in the same manner as `test()`. The test function given to `test.before()`
217262
```js
218263
test.before(t => {
219264
// this runs before all tests
220-
t.end();
221265
});
222266

223267
test.before(t => {
224268
// this runs after the above, but before tests
225-
t.end();
226269
});
227270

228271
test.after('cleanup', t => {
229272
// this runs after all tests
230-
t.end();
231273
});
232274

233275
test.beforeEach(t => {
234276
// this runs before each test
235-
t.end();
236277
});
237278

238279
test.afterEach(t => {
239280
// this runs after each test
240-
t.end();
241281
});
242282

243283
test(t => {
244284
// regular test
245-
t.end();
285+
});
286+
```
287+
288+
Both modern and legacy async support are available for hooks
289+
290+
```js
291+
test.before(async t => {
292+
await promiseFn();
293+
});
294+
295+
test.async.beforeEach(t => {
296+
setTimeout(t.end);
297+
});
298+
299+
test.afterEach.async(t => {
300+
setTimeout(t.end);
246301
});
247302
```
248303

@@ -251,12 +306,10 @@ The `beforeEach` & `afterEach` hooks can share context with the test:
251306
```js
252307
test.beforeEach(t => {
253308
t.context.data = generateUniqueData();
254-
t.end();
255309
});
256310

257311
test(t => {
258312
t.is(t.context.data + 'bar', 'foobar');
259-
t.end();
260313
});
261314
```
262315

@@ -265,12 +318,10 @@ The context is by default an object, but it can also be directly assigned:
265318
```js
266319
test.beforeEach(t => {
267320
t.context = 'unicorn';
268-
t.end();
269321
});
270322

271323
test(t => {
272324
t.is(t.context, 'unicorn');
273-
t.end();
274325
});
275326
```
276327

@@ -296,7 +347,6 @@ import assert from 'assert';
296347

297348
test(t => {
298349
assert(true);
299-
t.end();
300350
});
301351
```
302352

@@ -309,7 +359,6 @@ Just write your tests in ES2015. No extra setup needed.
309359
```js
310360
test(t => {
311361
t.pass();
312-
t.end();
313362
});
314363
```
315364

@@ -337,7 +386,6 @@ import foo from './foo'; // <-- foo can be written in ES2015!
337386

338387
test('foo bar', t => {
339388
t.same('baz', foo('bar'));
340-
t.end();
341389
});
342390
```
343391

@@ -385,31 +433,32 @@ test(async t => {
385433
});
386434
```
387435

388-
*You don't have to manually call `t.end()`.*
389-
390436
### Observable support
391437

392438
AVA comes with builtin support for [observables](https://github.com/zenparsing/es-observable).
439+
If you return an observable from a test, AVA will automatically consume it to completion before ending the test.
440+
*You don't have to use legacy `test.async` mode or `t.end()`.*
393441

394442
```js
395443
test(t => {
396-
return Observable.of(1, 2, 3).map(n => {
397-
t.true(n > 0);
398-
return n * n;
399-
});
444+
t.plan(3);
445+
return Observable.of(1, 2, 3, 4, 5, 6)
446+
.filter(n => {
447+
// only even numbers
448+
return n % 2 === 0;
449+
})
450+
.map(() => t.pass());
400451
});
401452
```
402453

403-
*You don't have to manually call `t.end()`.*
404-
405454
### Callback support
406455

407456
AVA supports using `t.end` as the final callback when using node-style
408457
error-first callback APIs. AVA will consider any truthy value passed as
409-
the first argument to `t.end` to be an error.
458+
the first argument to `t.end` to be an error. Note that `t.end` requires legacy `test.async` mode.
410459

411460
```js
412-
test(t => {
461+
test.async(t => {
413462
// t.end automatically checks for error as first argument
414463
fs.readFile('data.txt', t.end);
415464
});
@@ -461,7 +510,6 @@ Assertions are mixed into the test [context](#context):
461510
```js
462511
test(t => {
463512
t.ok('unicorn'); // assertion
464-
t.end();
465513
});
466514
```
467515

@@ -536,7 +584,6 @@ The following test:
536584
test(t => {
537585
const x = 'foo';
538586
t.ok(x === 'bar');
539-
t.end();
540587
});
541588
```
542589

@@ -564,7 +611,6 @@ test(t => {
564611
const b = 'bar';
565612
const c = 'baz';
566613
t.ok(a.test(b) || b === c);
567-
t.end();
568614
});
569615
```
570616

0 commit comments

Comments
 (0)