Testing with Ava.js

Today, we are less and less likely to meet projects that do not have requirements for the frontend code. A few years ago, no one even thought about it, and the requirements for the candidate were at the level – “Do you know how to typeset forms? You are accepted!”. And now any customer who respects himself and his clients requires developers to have the ability to cover their code with tests. It would seem, why? Testers will test, but not everything is so simple. In fact, covering the code with tests solves many problems even before the testing stage, which saves not only time for development, but also for the very testing. The product turns out better, is developed faster and, as a result, comes out cheaper for the customer.

At the moment, there are a great many libraries and tools for testing. In most cases and projects, you will see tools such as Mocha, Jest and others – they are all popular and good … But are there really worthy alternatives? Is there a lesser known library that can do its job better than the above flagships? Often, the popular tools listed above are used for testing.

My name is Mikhail, I’m a JS developer at SimbirSoft, and I would like to reveal such a little-known, but very useful and understandable tool as Ava. This is a simple library for running Node.js tests. In some moments, it surpasses its competitors, but for some reason it is much less popular. Perhaps for someone, Ava can be a great alternative at the start of a new project or solving a testing issue.

The article will be useful for both beginners who are just diving into the topic of writing tests, and experienced developers to broaden their horizons. And if you are a team lead or a tech lead and are starting a new project, perhaps this article will help you close the question “What to use as an alternative to popular code testing tools?”.

Benefits of Ava.js

To begin with, why do we need to write tests for our applications at all? After all, manual testing is much clearer, more convenient and faster. I threw a bunch into the code console.log, clicked there, clicked here – nothing seemed to be broken. Now click here – the request is gone, the answer is in, oh … a white screen. Error! Let’s go figure it out.

Now imagine that you have dozens or even hundreds of requests or functions that need to be tested. How would you feel about doing it manually? Probably something like this:

Now let’s look at how the Ava library can help us, and what advantages it has:

1) Elementary syntax and a simple API that provides just what you need.

2) A handy test report indicating the piece of code in which the error occurred and pointing out the specific difference between expected and actual results.

3) Speed. The advantage of this library is that all tests are run simultaneously, which significantly reduces their execution time.

4) Absence of implicit global variables.

Working with the library

So, let’s create a working directory for our test project, open a terminal and enter the following commands in turn:

mkdir ava-test-app

cd ava-test-app

npm install -y

npm install --save-dev ava

We changed to a directory, created a project with default settings, and installed Ava.

Next, open the file package.json and we see something like this:

{
    “version”: “1.0.0”,
    “description”: “”,
    “main”: “index.js”,
    “scripts”: {
        “test”: “echo \"Error: no test specified\" && exit 1”
    },
    “keywords”: [],
    “author”: “”,
    “license”: “ISC”,
    “devDependencies”: {
        “ava”: “^5.0.1”
    }
}

In this file, clear the field “test” and write the value there “ava”:

. . .
“scripts”: {
   “test”: “ava”
}
. . .

Thus, we can run testing using the library through the command npm test.

Finally, after installing the library, we have the opportunity to make our first test. Let’s create a file with the .js extension. and write in the terminal:

echo > test.js

Go to this file and write our test:

import test from “ava”;

test(“Пройден первый тест!”, t => {
   t.pass();
})

Next, in the terminal we write:

npm test

If you did everything right, then the test pass report should look like this:

> ava-test-app@1.0.0 test
> ava

√ Пройден первый тест!

1 test passed

Obviously, our test does not check anything, and the method pass just causes it to be passed. There is also a reverse method – fail. Let’s replace the method in the code pass on fail.

import test from “ava”; 

test(“Пройден первый тест!”, t => {
   t.fail();    // Заменили метод на fail
})

Run the test with npm test and see the following:

> ava-test-app@1.0.0 test
> ava

✕ [fail]: Пройден первый тест! Test failed via ‘t.fail()’

Пройден первый тест!

test(“Пройден первый тест!”, t => {
t.fail();
})

Test failed via ‘t.fail()’

> file:///test.js

1 test failed

The test ended with an error, and the place where it was made is highlighted
red. We also see a description of the reason why the test failed: “Test failed via `t.fail()`”. I don’t even think translation is needed here.

Let’s try something more difficult. Let’s create a file welcome.js in the same directory:

echo > welcome.js

With content like this:

class Welcome {

}

export default Welcome;

Let’s overwrite the file test.js.

import test from “ava”; 
import Welcome from “./welcome.js”;

test(“Пройден первый тест!”, t => {
   t.is(“Hello, world!”, Welcome.hello());
})

We run the test and see:

>ava-test-app@1.0.0 test
>ava

✕ [fail]: Пройден первый тест! Error thrown in test

Пройден первый тест!

test(“Пройден первый тест!”, t => {
t.is(“Hello, world!”, Welcome.hello())
})

Error thrown in test:

TypeError {
message: ‘Welcome.hello is not a function’,
}

> file:///test.js

1 test failed

In the console, we see the line highlighted in red in which the error occurred. We go down a little lower, where the description of the error is contained: “Welcome.hello is not a function”. The problem arose because the class Welcome missing function hello. So, let’s add:

class Welcome {
   static hello() {
      return “Hello, world!”
   }
}
export default Welcome;

Let’s run the test:

> ava-test-app@1.0.0 test
> ava

√ Пройден первый тест!

1 test passed

Everything is working! We can also write multiple independent tests. Let’s rewrite the Welcome class and add a couple more tests to the file test.js:

class Welcome {
   static hello(name = “world”) {
      return `Hello, ${name}!`
   }
}
export default Welcome;

import test from “ava”; 
import Welcome from “./welcome.js”;

test(“Пройден первый тест!”, t => {
   t.is(“Hello, world!”, Welcome.hello());
})

test(“Поприветствовали Ava.js”, t => {
   t.is(“Hello, Ava!”, Welcome.hello(“Ava”));
})

test(“Поприветствовали JS”, t => {
   t.is(“Hello, JavaScript!”, Welcome.hello(“Html”));
})

We get the result:

> ava-test-app@1.0.0 test
> ava

√ Пройден первый тест!
√ Поприветствовали Ava.js

✕ [fail]: Поприветствовали JS

Поприветствовали JS

test.js:13

test(“Поприветствовали JS”, t => {
t.is(“Hello, JavaScript!”, Welcome.hello(“Html”));
})

Difference (- actual, + expected):

- ‘Hello, Javascript!’
+ ‘Hello, Html!’

> file:///test.js:13:7

1 test failed

The library provides such a simple syntax and the most obvious test report that it’s easy to figure it all out, even if you are a novice developer and the photos look like this:

Non-obvious advantages of Ava and comparison of libraries

Consider a few more advantages of the Ava library. For example, no implicit global variables. Let’s compare it with another library for testing − Mocha. Below is one possible test for Mocha.

 var assert = require('assert');
describe('Array', function () {
  describe('#indexOf()', function () {
    it('should return -1 when the value is not present', function () {
      assert.equal([1, 2, 3].indexOf(4), -1);
    });
  });
});

We see that the test explicitly defines the variable assert. But where did the variables come from describe And it? These are the global variables that are provided to us by the library. Mocha. We will not delve into the problems of implicit global variables – this is a reason for a separate article. Note that such variables are hard to keep track of and can make debugging your code difficult.

At Ava there are no such problems because we have to “require” all variables.

Another undoubted plus of the library is the so-called Magic assertions (“Magic statements”). When you ran the tests above, you probably noticed that when the test fails Ava tells us the actual value “actual” and expected “expected”. These are the “magic statements” that help you quickly understand what exactly the error is.

Поприветствовали JS:
test.js:13

test("Поприветствовали JS", t => {
   t.is("Hello, Javascript!", Welcome.hello("Html"));
 })

Difference (- actual, + expected):


- 'Hello, Javascript!'
+ 'Hello, Html!'

The library works great with promises and asynchronous functions. Let’s add a couple more tests to our file test.js:

test("Асинхронные функции также работают:)", async t => {
    const flag = await new Promise((resolve) => (
        setTimeout(() => resolve(true), 1000)
    ))

    t.true(flag);
})

test("И еще один!", async t => {
   const batmanVoice = await new Promise((resolve) => (
        setTimeout(() => resolve("I am Batman!"), 500)
   ))
   t.is("I am Batman!", batmanVoice)
})

Everything works great:

✓ И еще один! (515ms)
✓ Асинхронные функции так же работают :) (1s)

Conclusion

We can conclude that Ava has a clear advantage over many other testing libraries (Mocha in particular). First of all, this is an elementary syntax that allows a beginner in testing to painlessly begin to cover his application with tests, and later, by gaining experience, switch to more powerful tools.

It is also worth noting another important advantage of Ava – the absence of implicit global variables. This helps a lot, especially for novice developers, to debug the code and not get confused in the abundance of implicit variables that appeared out of nowhere.

Ava is a test runner for Node.js focused on simple and lightweight testing. In addition to a clear and concise API with detailed error output, Ava includes new language features that allow you to create tests in a more efficient way.

We also publish useful materials for frontend developers in our social networks – VC And Telegram.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *