JavaScript Unit Testing Tutorial: A Comprehensive Guide

  • Learning Hub
  • JavaScript Unit Testing Tutorial: A Comprehensive Guide

OVERVIEW

Software testing is a very important aspect of software development. It ensures that the software under test meets the intended requirement and is free of errors and bugs.

Over the years, history has taught organizations how monetary values could be lost due to pushing error-prone and defective software to the market.

Software testing is important because software bugs can be expensive and dangerous to businesses and organizations. Over the years, history has recorded numerous potential software bugs resulting in monetary losses.

For instance, the Bloomberg terminal in London crashed due to a software glitch that affected more than 300,000 traders in financial markets. It forced the government to postpone a three billion pound debt sale in April 2015, according to TheGuardian.

Also, a vulnerability in Windows 10 lets users escape from security sandboxes through a flaw in the win32k system, according to WindowsReport.

In most cases, errors and bugs have been affected differently. This makes software testing an important stage in the Software Development Life Cycle (SDLC) phases.

In this JavaScript unit testing tutorial, we will explore a single type of software testing that every developer should perform to ensure the correctness of their codebase. It is called the Unit Test, and the software developers carry it out under test.

So, letā€™s get started!

What is Unit Testing?

Unit testing is a special software testing technique carried out by developers to test every single unit and component of the software under test. It is the smallest form of software testing because it checks every small unit of a larger software product.

It is performed by the developers and tests every single unit, including features, functions, methods, classes, and the overall functionality of a single feature of a software product.

In addition, unit testing is the only type of software testing because it is the closest to developers, and every professional developer should always carry out unit testing.

LambdaTest

Different Types of Testing

There are over 150 different types of software testing. However, listed below are the major testing types closest to software developers.

  • Unit testing
  • Integration testing
  • End-to-end testing

Unit Testing

This software testing basic approach is followed by the programmer to test the unit of the program. It helps developers know whether the individual unit of the code is working properly.

Unit Testing is very important for discovering and fixing bugs during development. Unit testing is the responsibility of developers because it's closest to development. It is the developers that create unit tests to test their production code.

There are two different approaches to unit testing. Either after writing your code before writing unit tests or before writing your actual code, the developer first creates a failing unit test. The second approach is called TDD (Test Driven Development).

Integration Testing

It focuses on the construction and design of the software. You need to see whether the integrated units are working without errors.

Integration testing is crucial as it tests different units, modules, or components of a software application as a combined entity.

If you're a front-end developer, you can use integration testing to test a complete component or feature as a single unit. Furthermore, as a backend developer, you can test a complete resource as a single unit instead of unit testing, where you have to test individual functions, methods, or implementations.

End-to-end testing

End-to-end testing (or E2E) is a methodology that assesses the working order of a complex product in a start-to-finish process.

It is a very complex testing method because it assesses the working order of a complex product in a start-to-finish process. For instance, you can use end-to-end testing to work through a complete website or checkout feature exactly how you intend your users to use the product to discover any bugs before pushing it to production for real users.

In most organizations, end-to-end testing is used to access a complete feature after developing in isolation with different developers in the team. A central repository system is used to build and combine the codebase. Next, end-to-end testing runs through the complete feature and ensures it works as intended before approving and pushing it to the stage.

In the next section of this JavaScript unit testing tutorial, we will explore the best practice in creating unit test cases and how you can set up unit tests with JavaScript.

Best Practices for Unit Test Creation

When creating unit test cases, you should follow these best practices to produce consistency and test every possible case properly.

  • Arrange, Act, and Assert (AAA)
  • Write deterministic tests
  • Write good test names
  • Write tests before or during development
  • Set up automated tests
  • Using Mocks and Stubs

Arrange, Act, and Assert (AAA)

The AAA approach is a recommended approach for structuring your unit test cases for readability. It improves your unit test readability by giving it a logical flow. It is sometimes called the ā€œGiven/When/Thenā€ protocol. You can use the AAA protocol to structure your unit tests with the following steps:

  • Arrange: Arrange the setup and initialization for the test.
  • Act: Act on the unit for the given test.
  • Assert: Assert or verify the outcome.

To demonstrate the AAA approach, take a look at this code snippet:

it('test for positive number', async () => {
// Arrange
const positive = 6;
// Act
const answer = Math.abs(positive);
// Assert
assert.equal(answer, positive);
});

The code shows the AAA protocol in action where the test case is arranged in that format. Next, we will look at writing deterministic tests.

Write deterministic tests

In software engineering, software testing comprises false positives and negatives, and we must be diligent in minimizing them.

Every unit test should have consistent output tests to verify the desired function. Deterministic tests should have a consistent behavior every time the test is run, provided the test code isn't changed.

The inconsistencies in testing can be called flakiness in tests. A situation where your test works or passes in development and fails with continuous integration. It hinders development, slows progress, hides design problems, and sometimes costs a lot of money. To avoid these, you can follow some of the Selenium best practices for efficient test automation.

Deterministic tests help understand every test case's output quickly and reduce hours of debugging for new team members.

Use good test names

In software engineering, one of the best practices for writing clean code is always having a good naming ability. As a developer, your variables, functions, methods, or classes should have good and descriptive names.

This best practice is also extended to writing test case names. It is important to have a clean and clear description of your test case to capture exactly when the test is supposed to check and the desired output.

For example, your test cases names should describe the purpose of your test cases as shown in the examples below:


describe("Test Names", () => {
it("is a Vue instance", () => {});
it("initializes with correct elements", () => {});
it("test for positive number", async () => {});
it('has a default message', async () => {});
it('can change message', async () => {});
)};

Write Tests Before or During Development

As a professional developer, you need to embed the concept of Test Driven Development (TDD) into your development process and workflow.

Test-driven development (TDD) is a software development process through which we enhance our test cases and software code in parallel.

The concept of TDD contradicts the traditional development process because, in TDD, developers must first write test codes before writing the actual software code to pass the test case. This approach ensures that when production code is written, it always compliments the test codes.

Additionally, BDD (Behavior-Driven Development) is another popular testing approach. This approach works well in rapid development settings and encourages more team collaboration to build a shared understanding of the problem.

Furthermore, with any approach you adopt in your project, you can still integrate continuous integration into your development pipeline to automate your software testing processes.

Leverage Automation testing

As a developer, integrating automated testing into your workflow saves a lot of time when compared to manually executing your test case every time before deployment.

You can use different automated testing frameworks to set it up. However, in this JavaScript unit testing tutorial, we will show you how to automate your unit testing with Selenium Cloud Grid.

Before we delve into automating our test cases with LambdaTest Grid, let's explore how to write a clean and proper test for JavaScript unit testing.

Using Mocks and Stubs

When creating test cases, you might be tempted to perform operations on the actual codes. For instance, if you made an API call to an external API, you might want to make such calls during testing to ensure everything works as planned. But that won't be considered best practice. You can use the Mock and Stub features of any test framework.

A stub is a dummy piece of code that lets the test run, but you don't care what happens to it, while a mock is a dummy piece of code that you verify is called correctly as part of the testā€”substitutes for real working code.

The beauty is that you can set them up and use them to test and verify your actual code works properly without making any expensive API calls or database manipulation. You can learn more about Mocking through this Mockito Tutorial For Unit Testing.

Getting started with JavaScript Unit Testing

As a developer, writing unit tests for your task is your responsibility. It should be part of your day-to-day activities as you code. In JavaScript, you can write unit tests the same way you write your real code using different testing libraries.

With these testing libraries, testing the functionalities and features of your project becomes very easy because the libraries include different assertion methods to carry out your checks.

Let's explore some of the most popular JavaScript testing frameworks you can use to write your unit test, integration test, and even end-to-end testing in this Selenium JavaScript tutorial.

Popular JavaScript testing frameworks

Various frameworks are helpful for unit testing in JavaScript. They are as follows:

  • Jest
  • Mocha
  • Jasmine
  • Karma
  • Cypress
  • Unit.js

Jest

Jest is one of the most popular testing frameworks for JavaScript. It was designed to work majorly with React and React Native-based applications. It is open-source and easy to get started. Jest reduces the extensive, time-consuming configuration needed to run software testing in the Frontend with JavaScript.

An assertion library for JavaScript, which runs on Node.js and the browser. It works with any test runner and unit testing frameworks like Mocha, Jasmine, Karma, Protractor (E2E test framework for Angular apps), QUnit, etc.

Some of the growth statistics of the Jest library as of the time of writing, according to GitHub, include more than 40.7k GitHub Stars and about 7.1m GitHub Usage, making it among the most popular testing framework for Jest testing.

Mocha

Mocha is a server-side and client-side testing framework for JavaScript and Node.js. The key features of Mocha are simplicity, flexibility, and fun. It makes asynchronous testing in JavaScript easy and fun. Mocha is designed to run serially, allowing for flexible and accurate test reporting and coverage.

Some of the growth statistics of the Mocha library as of the time of writing, according to GitHub, include more than 21.8k GitHub Stars and about 1.7m GitHub Usage, making Mocha a very popular testing framework.

Jasmine

Jasmine is a popular JavaScript behavior-driven development framework for unit testing JavaScript applications. It combines the power of speed and support for Node.js and the browser to become a robust testing framework for behavior-driven development testing framework.

Some of the growth statistics of the Jasmine library as of the time of writing, according to GitHub, include more than 15.5k GitHub Stars and about 2.5m GitHub Usage, making Jasmine among the most popular testing framework.

Cypress

Cypress is an end-to-end JavaScript-based testing framework that changes how developers approach software testing. It is built on Mocha, making asynchronous testing simple and convenient. In Cypress, unit tests can be configured to execute without running the web server.

This feature makes Cypress the ideal tool for testing a JavaScript/TypeScript library that is meant to be used in the browser, and setting up automated testing in your enterprise project is a breeze.

Some of the growth statistics of the Cypress library as of the time of writing, according to GitHub, include more than 41.5k GitHub Stars and about 618k GitHub Usage, making Cypress among the most popular testing framework.

In the next section of this JavaScript unit testing tutorial, we will explore how to write your unit test with JavaScript and how to run your test manually. Additionally, we will explore how to automate your testing suite with LambdaTest cloud Grid.

How to write a Unit Test in JavaScript?

Writing a unit test is simpler than you think using some of the popular testing frameworks listed above. In this section of this JavaScript unit testing tutorial, we will use the Jest framework to write some basic test cases.

We will write some unit test cases to check for ā€˜LambdaTestā€™ on Google and print the metadata on the terminal (once the search is completed).

Creating a project

First, clone the JavaScript Unit testing repository from GitHub, and add the following libraries to our package.json file.


bash 
npm install 
selenium web scrape

Before running the tests, please set the following environment variables in your .env file. You can find the username and access key on your LambdaTest Profile page.

For macOS:

bash
LT_USERNAME=
LT_ACCESS_KEY=
GRID_HOST=hub.lambdatest.com/wd/hub

After installing the libraries and setting the environment variables, open the search.js file to see how we implement a simple web scraping server.


const express = require('express');
const { Builder, By } = require('selenium-webdriver');
const app = express();
const port = 3002;
let driver;
app.get('/search', async (request, response) => {
 try {
   const data = await GoogleSearchWithLambdaTest();
   response.status(200).json(data);
 } catch (error) {
   response.status(500).json({
     message: 'Server error occurred',
   });
 }
});
const USERNAME = process.env.LT_USERNAME;
const KEY = process.env.LT_ACCESS_KEY;
const GRID_HOST = process.env.GRID_HOST;
const searchCapabilities = {
 build: 'JavaScript and Selenium Web Testing',
 name: 'Google Search',
 platform: 'Windows 10',
 browserName: 'Chrome',
 geoLocation: 'US',
 version: '90.0',
 selenium_version: '3.13.0',
 'chrome.driver': '90.0',
};
const searchGridUrl = 'https://' + USERNAME + ':' + KEY + '@' + GRID_HOST;
async function GoogleSearchWithLambdaTest() {
 try {
   driver = await new Builder()
     .usingServer(searchGridUrl)
     .withCapabilities(searchCapabilities)
     .build();
   await driver.get('https://www.google.com/search?q=lambdatest');
   const titles = await driver.findElements(By.id('rso'));
   return await getFirstTitle(titles);
 } catch (error) {
   throw new Error(error);
 } finally {
   await driver.quit();
 }
}
async function getFirstTitle(titles) {
 let allTitles = [];
 try {
   for (const title of titles) {
     const text = await title
       .findElement(
         By.xpath(
           '//*[@id="rso"]/div[1]/div/div/div/div/div/div/div/div[1]/a/h3'
         )
       )
       .getText();
     allTitles.push(text);
   }
 } catch (error) {
   console.log(error);
 }
 return allTitles;
}
app.listen(port, () => {
 console.log("Example app listening at http://localhost:${port}");
});

The above code snippet is a simple web scraping app we have created to search for the word "LambdaTest" on Google and retrieve all the search results' titles.

Code Walkthrough:

Letā€™s walk through the code together and understand the nitty-gritty of it.

Step 1: Add required packages and Set Up Express Server

First, we need the express and selenium-webdriver packages. Next, we create an Express server, initialize variables, and create our first endpoint to search the web page.

set up express server

Step 2: Initialize LambdaTest Capabilities

Next, we initialize LambdaTest properties, such as the username, access token key, grid host, and the capabilities used to perform the search.

javascript and selenium web testing

Step 3: Search the Web

Lastly, we use Selenium Builder to perform the web scraping procedure and retrieve all the elements that have the `rso` Id. Additionally, we call the `getFirstTitile` function to retrieve and convert all titles to an array.

 get first title

How to perform JavaScript Unit Testing?

Lastly, open the `tests/search.test.js` file inside the repository to explore how to write real-world unit tests with the Mocha and Assert JavaScript Framework.

Here is the code snippet:

const assert = require('assert');
const request = require('request');
let message;
beforeEach(async () => {
 message = 'LambdaTest: Most Powerful Cross Browser Testing Tool Online';
});
 
describe('Search', () => {
 it('can not can search google', async () => {
   const url = 'http://localhost:3002/search';
   request(url, function (error, response, body) {
     assert.equal(response.statusCode, 200);
     assert.equal(body[0], 'wrong title');
     done();
   });
 });
 
 it('can search google', async () => {
   const url = 'http://localhost:3002/search';
   request(url, function (error, response, body) {
     assert.equal(response.statusCode, 200);
     assert.equal(body[0], message);
     done();
   });
 });
});

Code Walkthrough:

Letā€™s walk through the code together and understand the nitty-gritty of it.

Step 1: Add required packages

First, we need the assert package and the search.js file, and next, we initialize our variables that will be used throughout the test inside the beforeEach script.

online cross browser testing tool

Step 2: Create a Describe block

A Describe block contains a collection of related test cases. We use the Describe block to group all our test cases since they are related.

describe block

Lastly, we included all the other test cases inside the Describe block. Each test case tests a particular behavior or implementation of a feature.

Running the Test

To run your test, type the following command into your root terminal.


bash
npm start
npm run test

After successfully performing running the test, you should be greeted with green passes for your test, like the screenshot below:

macbook pro selenium

So far, we have manually run the test with the command above to make sure that our test is passing before we move ahead to deploy.

We can also automate this process with the LambdaTest Grid, making it possible to implement a test strategy during deployment.

By providing a secure, scalable, and reliable cloud-based Selenium Grid Infrastructure, LambdaTest lets you perform cross browser testing at scale on 3000+ browsers & operating system combinations on an online browser farm.

You can follow the LambdaTest YouTube Channel for more such videos around Selenium testing, CI/CD, Cypress UI testing, and more.

Summary

Software testing is a very important aspect of software development. It ensures that the software under test meets the intended requirement and is free of errors and bugs.

The Unit Test, on the other hand, is a great software testing technique carried out by developers to test every single unit and component of the software under test. It is the smallest form of software testing because it checks every small unit of a larger software product.

In this JavaScript unit testing tutorial, we discussed a single type of software testing that every developer should perform to ensure the correctness of their codebase. We explored the different JavaScript Unit Testing libraries and showed their popularity using GitHub usage and stars.

We implemented a simple web scraping server to search a keyword on Google and retrieved all the search result titles. Lastly, we use Mocha to implement a simple unit testing method to ensure we retrieve the right titles from Google Search.

Are you a JavaScript developer interested in unit testing? Do you want the skills and knowledge needed to become an excellent JavaScript unit tester? If so, check out the Selenium JavaScript 101 certification from LambdaTest.

Frequently Asked Questions (FAQs)

Can JavaScript be unit tested?

JavaScript Unit Testing is a method where JavaScript test code is written for a web page or web application module and executed in the respective browsers to test if all functionalities are working as desired.

What are the challenges in JavaScript unit testing?

When it comes to JavaScript, one of the biggest challenges in writing unit tests is finding an automated way to test asynchronous code. Many JavaScript libraries contain callback functions, which fire after an asynchronous operation has been completed. These callbacks are often used as the basis for complicated operations that may take a significant amount of time to complete, such as building a user interface or fetching data from a database.

Was this article helpful?

Helpful

NotHelpful