Unit testing with Jest (Part 1)

Before this internship I’ve never written tests for my code. I didn’t think it was necessary because if something doesn’t work in your code it either crushes and can see errors in JS console or you don’t get expected behavior or result. But in the Add-on Linter project I’m working on now having a test suite is really important:

  • First of all on this project is working a group of developers and there is always a fear of breaking a code by making changes or adding new features to the code that you didn’t write or did write but forgot all it’s quirks.
  • Also writing tests and thinking about all possible scenarios might pinpoint problems in a code and fix them before going into production phase.
  • And last but not least with tests, you are more able to change code throughout the lifetime of an application. Tests provide a safety net, allowing you to refactor at any time without fear of breaking existing code, so you can add new methods, features or syntactic sugar.

Jest

In Add-on Linter project we use a JavaScript testing framework Jest. It comes with a test runner, assertion library and mock functions.

For a function sum:

function_sum

Jest test looks something like this:

test_sum

 

 

Here, we’re simply testing that + 2 equals 3. Let’s walk through this syntax:

  • Each test begins with Jest’s built-in test() method.
  • test() always includes an string argument describing what we’re testing for. Above, we’re testing that function sum “adds 1+2 to equal 3”. Writing good, clear, descriptive explanations of what we’re testing is important.
  • In the expect() line, we detail what we’re expecting to occur. This function is used every time we want to test a value.
  • Jest’s expect() function is rarely used alone. We usually include it alongside something called a matcher or matcher function that asserts something about the value we’re testing. In the example above, toBe() is our matcher function. It checks that the value is strictly equal to what we expect. ie: that + 2 is strictly equal to 3.
  • If the value provided as an argument to expect() (+ 2) is equal to the value provided as an argument to toBe() (3), our test passes. If not, it fails.

If the test passes we see:

test_pass

In case of test failure we see:

test_fail

Expanding the unit testing coverage

But even for this simple function sum there are lots of scenarios that we haven’t tested. We would like to catch cases when the function stops working in case if someone modifies it’s implementation down in the future.

So let’s expand the testing coverage by creating additional unit tests:

add_tests

Here we use describe(name, fn) block that groups together several related tests in one “test suite”. We added 3 additional test cases besides the initial one, varying the inputs to the function, including a case where sum function throws an error. To test that the function throws this exact error we use .toThrowError(error) matcher.

Matchers

Jest uses “matchers” to test values in different ways. You can find a complete list of matchers here.

Most common of them these:

  • .toBe(value) – checks the exact equality of  two values. In case of objects it checks if it’s the same object according to memory references.
  • .toEqual(value) – checks that two objects have the same key/value pairs.
  • .toBeFalsy() , .toBeTruthy()  – check to ensure that value is false/true in a boolean context.
  • .toBeInstanceOf(Class) , .toHaveProperty(key, value) –  checks for an object.
  • .toContain – checks if an item is in an array or whether a string is a substring of another string.
  •  .toThrow(error) – checks if a function throws an error when it’s called.
  • .not –  chain this matcher with any other to check the opposite.

This concludes my introduction to Jest unit testing.

 

Advertisements

Breaking down the issue

In the previous post I described the project and the issue I’m working on as a part of Mozilla Outreachy program. Now I would like to go through the process of solving this issue.

So the issue I’ve been assigned to close in this project formulated as Convert code-base to async-await

This is a large task and will require being broken down into smaller pieces:

  • Check and update Babel transpilation steps to be async/await aware;
  • Convert source code to use async/await (leaving the tests as promise based initially)
  • Once the source code is converted and the existing test suite passes, modify the tests to use async/await too.

Let’s go through each step more thoroughly.

Babel

Babel is a JavaScript transpiler best known for its ability to turn the next version of JavaScript into plain old ES5 JavaScript that can run in any browser (even the old ones). It makes available all the syntactical sugar that was added to JavaScript with the new specifications, including support for async/await.

Following plagins should be included into Babel configuration:

  • Syntax-async-functions – this plugin allows Babel to parse async/await syntax;
  • Transform-async-to-generator – turns async functions into ES2015 generators;
  • Transform-runtime – does three things: 1)  Automatically requires babel-runtime/regenerator when you use generators/async functions; 2)  Automatically requires babel-runtime/core-js and maps ES6 static methods and built-ins;          3) Removes the inline Babel helpers and uses the module babel-runtime/helpers instead.

Conversion

There are 3 main things to understand in order to convert Promises into async/await syntax:

1. The word async before a function means that a function always returns a Promise. And any function that returns a Promise it can be converted to async function like this:

2

2. The keyword await makes JavaScript wait until Promise settles and returns its result. So we need to replace .then calls by await.1

3. If a Promise resolves normally, then await returns the result. But in case of a rejection we can catch that error using try..catch block.

5

Tests

Though tests have their own syntax, the rules for refactoring are the same:

4

Introduction to the Project and the Issue

Non-technical part

It’s been almost 2 weeks since I’ve started Mozilla internship. I’ve received new MacBook, I’ve got acquainted with the project and been given an issue to work on, I refreshed my knowledge, made a plan how to proceed and dived into it. Now about all of it in more details.

First of all, it was a pleasant surprise to receive MacBook from Mozilla to work on for the duration of this internship. I didn’t expect it, but I’m beside myself with glee that I got it, and it certainly set some kind of  ‘professional developer’ mood for me.

Going further, it was great to meet my mentor and find him really easygoing about the process of the internship, especially given our 6-hour time difference.

So, let’s talk about the project and the issue I’ve been assigned.

The project

First of all, the project I’m working on is called Addons-linter

Add-ons allow developers to extend and modify the functionality of Firefox. They are written using standard Web technologies – JavaScript, HTML, and CSS – plus some dedicated JavaScript APIs. Among other things, an add-on could:

  • Change the appearance or content of particular websites
  • Modify the Firefox user interface
  • Add new features to Firefox

All add-ons listed on addons.mozilla.org (AMO) are required to pass a review by Mozilla’s add-on review team, and the first step in this process is automated validation using the Add-ons Validator.

The validator alerts reviewers to deprecated API usage, errors, and bad practices. Since add-ons can contain a lot of code, the alerts can help developers pinpoint the bits of code that might make your browser buggy or slow, among other problems. It also helps detect insecure add-on code. It helps keep your browsing fast and safe.

In a nutshell the way the linter works is to take an add-on package, extract the metadata from the xpi (zip) format and then process the files it finds through various content scanners.

Architecture diagram

Scanners

Each file-type has a scanner. For example: CSS files use CSSScanner; Javascript files use JavaScriptScanner. Each scanner looks at relevant files and passes each file through a parser which then hands off to a set of rules that look for specific things.

Rules

Rules get exported via a single function in a single file. A rule can have private functions it uses internally, but rule code should not depend on another rule file and each rule file should export one rule.

Each rule function is passed data from the scanner in order to carry out the specific checks for that rule it returns a list of objects which are then made into message objects and are passed to the Collector.

Collector

The Collector is an in-memory store for all validation message objects “collected” as the contents of the package are processed.

Messages

Each message has a code which is also its key. It has a message which is a short outline of what the message represents, and a description which is more detail into why that message was logged. The type of the message is set as messages are added so that if necessary the same message could be an error or a warning for example.

Output

Lastly when the processing is complete the linter will output the collected data as text or JSON.

The issue

The issue I’ve been assigned to close in this projects formulated as Convert code-base to async-await

What that means is that now the code -base of Addons-linter  is heavily Promise based. This issue is to convert all the Promise-based code to instead use  async/await syntax.

Why do we need to do that? Because Promises chains could be long and difficult-to-read blocks of code. For example:

function promiseChain () {
  const api = new Api()
  return api.function1()
    .then((value1) => {
      //do something
      return api.function2(value1)
    })
    .then((value2) => {
       //do something
      return api.function3(value2)
    })
    .then((value3) => {
      console.log(value3)
    })
}

Async/await is a new syntax that allows us to compose Promises as though they were just normal synchronous functions without callbacks. It’s a fantastic addition to the Javascript language, and can be used to simplify pretty much any existing JS application.

async function asyncAwait () {
  const api = new Api()
  const value1 = await api.function1()
  const value2 = await api.function2(value1)
  const value3 = await api.function3(value2)
  console.log(value3)
}

As you can see from the structure of Addons-linter I have a lot of files to work through and I think that after I completed this work I will be able to write async functions in my sleep 🙂

The letter of acceptance

outreachy

Today I got a letter informing me, that my application to Outreachy program was approved and I was accepted into internship. This is a huge step for me and I hope a start of my career as a web-developer.

I don’t have an education in computer science field, my major is electrical engineering , but when I got really bored with my paper-wasting engineering job, where I could never see the results of my work, I decided to learn the craft of the future – web-development.

I know that a lot of web-developers are people without any specialized education, that they just learned all of it by themselves, but for me this self-educating process turned out to be harder than I expected. There are a lot of suggestions in the web about how to become a web-developer. Perhaps even to much. Because for the last 1,5 years I took different online classes, tried to learn different languages and frameworks, switched from front-end to back-end and back and ended up at the place where I’ve heard about a lot of things, done some of them, but real good at none.

So I hope that this internship with Outreachy will become the real foundation for my career and I’ll try to describe to the best of my abilities the 3 months I’ll be in this program, my learning process and everyday thoughts, my development struggles and ways of finding solutions.

Let the trip begin!

outreachy_road