Categories
Node.js Best Practices

Node.js Best Practices — Testing and Quality

Spread the love

Node.js is a popular runtime to write apps for. These apps are often production quality apps that are used by many people. To make maintaining them easier, we have to set some guidelines for people to follow.

In this article, we’ll look at testing and maintaining the quality of Node.js code.

Write API (Component) Tests at Least

We should write tests as soon as we have time to do it. Tests prevent regressions by checking that existing functionality is still working. That way, we don’t have to worry about our code changes breaking any critical functionality.

It’s easy to create tests for our app. We can use test frameworks like Jest and libraries like Superagent to test our APIs.

Also, we should make sure that code coverage is high so that we’re actually testing most of our code with our tests.

For instance, we can add tests easily to an Express app with Jest and Supertest by running:

npm i jest supertest

Then we write the following:

index.js :

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', (req, res, next) => {
  res.json({hello: 'hello'});
});

module.exports = app;

index.test.js :

const request = require('supertest');
const app = require('./index');

describe('hello test', () => {
  it('/ should return hello response', async () => {
    const res = await request(app)
      .get('/')
    expect(res.statusCode).toEqual(200)
    expect(res.body).toEqual({hello: 'hello'})
  })
})

In the code file, we added supertest to our index.test.js test file. Then we test our route by making a request to the / route and checking the response code and body.

The toEqual method checks for deep equality so that we can check for any value.

Include 3 Parts in Each Test Name

Each test name should include 3 parts so that people reading the test cases know what’s being tested. A test name should include what is being tested, what scenarios, and what’s the expected result.

Structure Tests by the AAA Pattern

AAA stands for Arrange, Act, and Assert. The first part of the test should set up the data for our tests. Then we actually run the code, and then assert that the returned result is what’s expected.

With these kinds of tests, we understand the main code just by looking at the tests.

Detect Code Issues with a Linter

We should use a code linter to check for basic quality issues with our code. Spacing, formatting, and syntax errors are within its domain. It also checks for common antipatterns to make sure that our code don’t have them. Linters with Node add-ons can also check for security issues with our code.

It’s easy to overlook them without a linter. So we may be running bad quality and code with security vulnerabilities in our code.

Avoid Global Test Fixtures and Seeds

Each test should have its own test fixtures and seeds so that they run independently without anything else. This is important because we need tests to be testing things without depending on anything external. It makes tests easy to add and debug.

It reduces lots of headaches with tests. They shouldn’t depend on any external dependencies.

Inspect for Vulnerable Dependencies

We can use npm audit or snyk.io to check for vulnerable dependencies so that we update those packages as quickly as possible.

With these automated tools, we can check for vulnerable packages without doing anything ourselves.

Tagging Tests

Tagging tests let us search for them easily. We can add the tags to the test names so that we can find them easily.

Check Test Coverage

Test coverage lets us check if tests are running enough parts of our code. Code coverage tools provide highlights to see which parts of the code have been run by tests and what hasn’t. Then we can look at what kinds of code that we need to run with our tests to increase test coverage of our code.

We may also want to fail the build if test coverage falls below a certain threshold.

Inspect for Outdated Packages

We can check for outdated packages with npm outdated and npm-check-updates to detect outdated packages. We can also run it in our CI pipeline to prevent the build from succeeding if we have outdated packages.

This way, we won’t be using outdated packages in our app.

Conclusion

Adding tests is easy with Node apps. It lets us check for regressions without much effort. When we divide our tests to test small pieces of the code, then adding tests takes little effort. This is especially easy with test frameworks like Jest and test HTTP clients like Superagent.

We should also check for vulnerable packages and update them as soon as possible. In addition, we should check our own code for security vulnerabilities and fix them as soon as possible.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

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