AVA Testing Tutorial: A Guide to Lightweight Testing

Time for yet another installment in the loose series where we cover JavaScript testing tools. Today's post is an AVA…

AVA Testing Tutorial
Testim
By Testim,

Time for yet another installment in the loose series where we cover JavaScript testing tools. Today’s post is an AVA testing tutorial: it features a guide on how to install and use this test runner in order to achieve uncomplicated, lightweight testing.

AVA is a test runner for Node.js. It allows you to run your JavaScript tests concurrently. It boasts a simple syntax, “no implicit globals,” magic assertions, promise and async function support, observable support, and enhanced assertion messages.

In this post, we’ll walk you through some of the features above. We start by showing you how to install and setup AVA. Then, we proceed to showcase some of its most important features quickly and wrap-up with final tips and advice.

Let’s get started.

Installing AVA

Installing AVA is super easy: you do it by using npm. So, before anything else, you must have Node.js installed. Go and install it if you don’t already have it. After you’re all set, you can install AVA by running the following commands in your terminal window:

mkdir ava-sample-app
cd ava-sample-app
npm init ava

The three lines of code above should be easy to understand. In the first line, we create a new directory to house our sample project. The second line enters the directory. Finally, the third line initializes a new project using AVA.

After the third line finishes executing, you should see some new files hanging around in the folder. Open the package.json file and verify whether it looks like this:

{
	"scripts": {
		"test": "ava"
	},
	"devDependencies": {
		"ava": "^2.4.0"
	}
}

With the exception of version numbers, your file should look exactly like the code above. If it doesn’t, you might have to try again.

Writing Your First AVA Test

With AVA installed and setup, we’re ready to write our first test. In under a minute, you’ll be testing with AVA.

Using the text editor of your preference, create a file called test.js in the project root directory, and add the following content to it:

import test from 'ava';

test('foo', t => {
	t.pass();
});

If everything went well, you should see a message stating that one test passed.

Congratulations! You’ve just written your first AVA test.

Incrementing Our Test

As you’ve probably noticed, our first test doesn’t really test anything. It’s just a single assertion that we’re forcing to pass. Now, we’re going tweak it in a few different ways, so you can get a feel of what a test in AVA feels like.

Making the Test Fail

In our first example, we force the test to pass. Now, let’s do the opposite so that we can see the test failing:

import test from 'ava';

test('foo', t => {
	t.fail();
});

We’ve just replaced “pass()” with “fail().” The test is now supposed to fail.

Now rerun the test, and you should see something like this:

Of course, it’s also possible to make a test pass or fail by performing a comparison in the assertion. The following code asserts that 2 + 2 should be equal to 4:

import test from 'ava';

test('foo', t => {
	t.is(2 + 2, 4);
});

Let’s now replace the 4 with 5 to see the test fail:

A Tour of AVA’s Best Features

You’ve just seen how to install AVA and get it up to speed. Also, you’ve learned how to create and run your first test using AVA. Now, as promised, we’re going to take you on a journey through some of AVA’s most exciting features. Let’s begin.

No Implicit Globals

The first item in our list is “no implicit goals.” That’s a promise AVA makes,  but what does that mean? Consider Mocha, another JavaScript testing framework. A basic test might look something like the following example code:

var expect = require('chai').expect;
describe('Array#indexOf', () => {  
  it('should return -1 when the value is not present', () => {
    expect([50, 60, 70].indexOf(52)).to.be(-1);
  });
});

We can see that the test defines the expect variable, but what about the describe and it keywords? Where do those come from? Those are “implicit globals” provided to you by mocha. It’s out of the scope of this article to talk about all the problems of implied globals in JavaScript in general, but suffice it to say, implied global variables are hard to track and make it more difficult to debug and reason about your code. Technically, you as the developer are burdened with knowing all the things that are being injected into your tests via implied globals with Mocha. With AVA, you are in control because you must “require” everything. That’s the beauty of a promise like “no implicit globals.”

Magic Assertions

Another cool feature of Ava is “magic assertions”. Have you ever had a test fail and found it hard to even see what the failure was? Not so with AVA! You can see in the image below that it will not only syntax highlight the code “diff”, but also visually show you the expected versus actual result (“magic assertion”).

Promise and Async Function Support

AVA also takes into account modern JavaScript features such as promise and asynchronous function support.  AVA will wait for a promise to resolve before ending the test. You may be wondering if this will slow down your tests. It won’t because…

The support for asynchronous functions is built-in. An example below shows this clearly.

test(async function (t) {
	const value = await myPromisedFn();
	t.true(value);
});

// Async arrow function
test('promises the truth', async t => {
	const value = await myPromisedFn();
	t.true(value);
});

Observable Support

An Observable is a data type that can be used to model push-based data sources such as sockets and timer intervals, among others. It’s great if you’re trying to emit a bunch of streamed values.

The nice thing AVA does for you is consuming an Observable to completion before ending the test (i.e., it gets all the values you’re expecting).

Enhanced Assertion Messages

AVA comes with power-assert library built right in, so you get the benefit of enhanced assertion messages.

Below is a standard assertion example from Node’s standard assertion library:

const a = /foo/;
const b = 'bar';
const c = 'baz';
require('assert').ok(a.test(b) || b === c);

// AssertionError: false == true

But with AVA’s enhanced test assertion the following test produces a much more detailed assertion message.

For example:

test('enhanced assertions', t => {
	const a = /foo/;
	const b = 'bar';
	const c = 'baz';
	t.assert(a.test(b) || b === c);
});

produces:

6:   const c = 'baz';
7:   t.assert(a.test(b) || b === c);
8: });

Value is not truthy:

false

a.test(b) || b === c
=> false

b === c
=> false

c
=> 'baz'

b
=> 'bar'

a.test(b)
=> false

b
=> 'bar'

a
=> /foo/

AVA Testing for Fun and Profit

The JavaScript ecosystem is vibrant and always evolving and, fortunately, testing is taken seriously in that space. Proof of that is the number of test runners, frameworks, and libraries available for you to test your applications written with Node, React, Angular and also, of course, with vanilla JavaScript. The number of such tools grows with each passing year and such growth shows no sign of slowing down.

In today’s post, we’ve covered yet another tool in that space: AVA. AVA is a test runner for Node.js with a focus on allowing easy, lightweight testing. Besides offering a clear and concise API that features detailed error output, AVA embraces new language features that allow you to create your tests in a more effective way.

What should be your next steps? Well, if you want to learn more about AVA, then search around. There are countless resources available, both free and otherwise.

Also, stay tuned to the Testim blog. This is a place where we often publish new content about testing tools, techniques, and processes related to JavaScript and front-end testing.