Blog

Effective Guide to Write Testable JavaScript

  • by Sophia
  • 2 years ago

With the growth in technology, we have earned better options for unit testing JavaScript. Whether we are using Node paired with a test framework like Mocha or Jasmine, in a headless browser, we have a variety of options. However, it does not mean that the code which is tested is as easy on us as our tools are!

Organizing and writing code is easily testable and requires some efforts, but functional programming concepts are inspired by few patterns which can help in testing our code.

Here in this article, we will go through some useful tips and patterns for writing testable code in JavaScript.

Keep Business Logic and Display Logic Separate

JavaScript­based browser application primally listens to DOM events which is triggered by the end user. It is always tempting to write an anonymous function that does maximum work right while setting up DOM event listeners. This can create aloft both in lines of code and the time for practising. So, it is recommended to, write a named function and pass it to the event handler. This applies to more than the DOM, though. Many APIs, both in the browser and in Node, are serving this purpose.

// hard to test

$('.show').on('click', () => {

   $.getJSON('/filepath')

        .then(data => {

              <span class="dollar">$('#output­list').html('output: ' + data.join(', '));

        });

});

// testable; we can directly run fetchList to see if it

// makes an AJAX request without triggering DOM

// events, and we can run showList directly to see that it

// displays data in the DOM without AJAX request

$('.show').on('click', () => fetchList(showList));

function fetchList(callback) {

   $.getJSON('/filepath').then(callback);

}

function showList(data) {

   <span class="dollar">$('#output­list').html('output: ' + data.join(', '));

}

Use Callbacks or Promises with Asynchronous Code

In the above example, refactored fetchThings function runs an AJAX request. It means that we can’t run the function and test because we didn't know when it had finished running. The common way to proceed is to pass a callback function as a parameter to the function that runs asynchronously.

Apart from this, you may also use the Promise API to organise asynchronous code. Fortunately, $.ajax and most other of jQuery’s asynchronous functions return a Promise object already, so a lot of common use cases are already covered.

// hard to test; we don't know for how long the AJAX request will stay

function fetchResult() {

   $.ajax({ url: '/filepath' });

}

<p class="commnt
">// testable; by passing a callback and run assertions

function fetchResultWithCallback(callback) {

   $.ajax({

      url: '/filepath',

      success: callback,

   });

}

<p class="commnt
">// also testable; run assertions after the returned Promise resolves

function fetchResultWithPromise() {

   return $.ajax({ url: '/file_path' });

}

Avoid Side Effects

Avoid writing functions that alter external state while running. It prevents side effects that could affect your ability to test other code with confidence. Rather it is best to keep side effects as close to the edges of your code as possible, with as little “surface area.”

// hard to test; we have to set up a globalListOfBikes object and set up a

// DOM with a #model­list node to test this code

function processBikeData() {

    const models = globalListOfBikes.map(bike => bike.model);

    $('#model­list').html(models.join(', '));

}

// easy to test; pass an argument and proceed to test its return value, without

// set any values on the window or check the DOM the result

function buildModelsString(bikes) {

    const models = bikes.map(bike => bike.model);

    return models.join(',');

}

Don’t change Parameters

Create a new object or array in code and then proceed to add values to it. Or, use Underscore or Lodash to clone the passed object or array before using on it.

// alters objects passed to it

function upperCaseLocation(clientInfo) {

    clientInfo.location = clientInfo.location.toUpperCase();

    return clientInfo;

}

// sends a new object back instead

function upperCaseLocation(clientInfo) {

    return {

        name: clientInfo.name,

        location: clientInfo.location.toUpperCase(),

        age: clientInfo.age

    };

}

Writing Test before Coding

A test driven development (TDD) is the process of writing unit tests before the code. In practice, TDD is a method that can be difficult to commit to all your code changes. But when it seems worth trying, it’s an excellent way to guarantee you are keeping all code testable.

I hope these tips will help you remember, to keep your code simple and functional, this will keep your test coverage high and overall code complexity low!


Author Bio :

Sophia is a trained WordPress developer working with WordPrax Ltd.­ A leading HTML to WordPress conversion services company. If you're planning to convert HTML website to WordPress for a brilliant online presence, she can help you. Some stunning articles related to website markup conversions can be found under her name.

Social Profiles :

https://twitter.com/WordPrax

https://www.facebook.com/wordprax

https://www.pinterest.com/Wordprax/