In this article I want to introduce you to a new library for testing AVA . Relatively new, it is already more than 2 years old, and it has acquired a solid number of plug-ins and of course the community that develops it. We will look at the library functionality. Set up the environment and write a couple of tests to look at the library in action.
First of all, the library offers speed. Tests are run in parallel, which accelerates the execution of tests. As an example, the Pageres project is given in which testing was postponed to AVA , which gave an increase of almost 3 times (31 seconds were and 11 became). Tests do not depend on the global state and on other tests, which of course simplifies testing. Out of the box, es2015 is immediately used.
Install the appropriate npm module. Set as a dependency to work in a specific folder.
// package.json ..., "scripts": { "test": "ava" }, ...
npm install -D ava npm test
or globally
npm i -g ava ava
It's time to write the first test, take an example from the official repository. And save it as my-tests.js
import test from 'ava'; test('foo', t => { t.pass(); }); test('bar', async t => { const bar = Promise.resolve('bar'); t.is(await bar, 'bar'); });
Immediately we see the use of es2015 with arrow functions, let and async. In my opinion, the minimalist syntax was not deceived.
Run tests
npm test my-tests.js // or ava my-tests.js
And we get the result
2 passed
If we want to see more detailed information about each test, we can use the parameters for the module
ava my-tests.js --verbose // or ava my-tests.js -v
foo bar 2 tests passed
We can also run watcher to develop TDD style.
ava my-tests.js --watch // or ava my-tests.js -w
You can see the full list of parameters
ava --help
Simple test:
test('description', t => { });
One of the most common situations when you need to perform only one test of all:
test.only('test only', t => { t.pass(); });
Skip the test, you may need to refactor, search for errors:
test.only('test only', t => { t.fail(); });
Delivered to the API level, which is very interesting. You can make a reminder right in the tests.
test.todo('');
If we need to test the asynchronous part of the code, we can use "cb":
test.cb('callback', t => { setTimeout(function() { console.log('time'); t.end(); }, 3000); });
The serial parameter allows us to perform tests in a specific sequence. For example, we want to check the existence of a configuration file. If not, you need to create it. We will do 2 tests, one will create our file, and the second to check.
And it will be more convenient for us that they start exactly in sequence.
import test from 'ava'; import fs from 'fs'; const path = 'serial-test-one.txt'; test.cb('serial 1: create file', t => { fs.writeFile(path, 'test', function(err) { if (err) { t.fail(); } else { t.pass(); } t.end(); }); }); test.cb('serial 2: is file exists', t => { fs.access(path, fs.F_OK, function(err) { if (err) { t.fail(); } else { t.pass(); } t.end(); }); });
By writing this code we get
serial-one › serial 2 serial-one › serial 1 2 tests passed
And we see that the tests started and ended successfully. But this is not correct, this code does not guarantee the execution in the order we need. If we simulate a situation when there is no file yet, skip the creation test, we will get an error
- serial-one › serial 1 serial-one › serial 2 Test failed via t.fail() 1 test failed 1 test skipped 1. serial-one › serial 2 AssertionError: Test failed via t.fail() serial-one.js:19:9 FSReqWrap.oncomplete (fs.js:123:15)
To ensure consistency, we can use the --serial or -s option.
ava serial-one.js -s serial-one › serial 1 serial-one › serial 2 2 tests passed
Or use
test.cb.serial('serial 1', t => { ... });
The test falls and we know about it. We can clearly indicate this.
test.failing('failing', t => { t.fail(); });
As a result, we see that this test falls, but we know about it, and ideally we are already doing something.
1 known failure
Very pleased that we can combine the parameters. This allows us to implement tests of any complexity and run in only the necessary and in the right order.
test.only.cb test.cb.only
To configure the test environment there are before and after. They will be executed once at the start of test execution and at the end, respectively.
test.before(t => { }); test.after(t => { });
We can also declare several such functions and they will be called in the order of adding
test.before(t => { console.log('before'); }); test.before(t => { console.log('before#2'); }); before before#2
Works for after.
If the text falls, after are not called. To remedy the situation you need to use the always modifier.
test.after.always(t => { });
When we need to set up the environment before each test, we use beforeEach and afterEach.
test.beforeEach(t => { }); test.afterEach(t => { });
For them, the same behavior as for before and after is preserved: the declaration order and, if there is an error in the test, the after are not called (if there is not always).
test('test', t => { t.pass(); t.skip.fail(); t.truthy(true); t.truthy('unicorn'); t.falsy(false); t.falsy(1 === 0); t.true(true); t.false(false); t.is(1, 1); t.not(1, 0); t.deepEqual([0, 1, 2], [0, 1, 2]); t.notDeepEqual([0, 2, 2], [0, 1, 2]); });
Very convenient deepEqual, and the ability to skip the check.
Separately, we consider the error output, it is very detailed.
test(t => { const a = /foo/; const b = 'bar'; const c = 'baz'; t.true(a.test(b) || b === c); });
t.true(a.test(b) || b === c) | | | | | "bar" "bar" "baz" false
Which certainly helps debugging.
Before exploring AVA, I wrote tests on Jasmine . I like the Behavior-Driven style. For this AVA has a plugin ava-spec .
npm i -D ava-spec
Then we can write tests like this.
import {describe} from 'ava-spec'; describe('module#1', it => { it('can look almost like jasmine', t => { t.deepEqual([1, 2], [1, 2]); }); it.todo('todo'); it.skip('fail', t => { t.fail(); }); });
We can customize information about our tests. I liked the tap-summary .
npm i -D tap-summary
We use
ava ava-spec.js -t | tap-summary
Let's make a function, put it in a separate file, connect it and test it.
// ./test/sum.spec.js import { describe } from 'ava-spec'; import sum from '../src/sum'; describe('sum', it => { it('should return 10', t => { const expected = 10; const actual = sum(3, 7); t.is(actual, expected); }); });
// ./src/sum.js function sum(x, y) { return x + y; } module.exports = sum;
ava test/sum.spec.js
Everything works, our code from the file is connected and tested. But there is a problem, our code is written on ES5, and tests are ES6. Let's fix this situation. AVA out of the box uses Babeljs . And for our code, we will use it too. Configuring configs.
// .babelrc { "presets": [ "es2015" ] }
and for AVA. The AVA config is right in package.json.
// ./package.json ..., "ava": { "babel": "inherit", "require": [ "babel-register" ] }, ...
We launch without changes.
ava test/sum.spec.js
AVA provides an excellent test development platform. This library has everything for it: minimalistic style, quick execution, flexibility in writing tests, work with tests and the environment for them, informative error output. In total, with the ability to customize both the test code itself, based on preferences and necessity, and the output of information on tests.
I would like to tell a little bit about the author of this library. This is probably one of the most famous people in the JS community of Sindre Sorhus . On his page on github you can look at his projects and treasure in the community. And / or you can get to know him as a person, as far as possible on the Internet, or ask question / s through ama - Ask me anything! .
Useful links:
Source: https://habr.com/ru/post/313468/
All Articles