JavaScript Unit Testing Tutorial
By Neha Vaidya, Community Contributor - April 11, 2023
In the testing world, checking a single functionality differs from testing a whole application end-to-end. While both are equally important, testing each functionality (also known as a unit) is necessary to ensure that every function in the application performs as expected. This is where unit testing comes in.
As of 2022, 98% of websites use JavaScript as a client-side programming language, which shows its increasing popularity.
Since JavaScript or JS is a popular and ever-evolving programming language used for the development of web applications, it becomes necessary to learn how one can perform unit testing in JavaScript. This article will explore how to perform these tests, where precisely these tests should run, and why.
What is a Unit Test?
A unit test verifies the behavior of a software unit in the system. It verifies whether a small and isolated piece of the codebase called “unit” behaves as the developer intended.
- Unit tests verify an application’s smallest parts or components by comparing their actual behavior with the expected behavior in complete isolation.
- Here, “complete isolation” means that, during unit testing, devs do not connect the application with external dependencies such as databases, the filesystem, or HTTP services.
- This allows unit tests to be fast and stable since they won’t fail due to problems integrating with those external services.
Why write Unit Tests?
Usually, developers write unit tests first, then write the software code. This approach is known as test-driven development (TDD).
- In TDD, the requirements are turned into specific test cases; then the software is improved to pass the new tests.
- In the case of unit tests, it allows for code modification without affecting the functionality of other units or the software. This makes the job easier for developers as the bugs are easy to locate at this stage, which saves time and money.
- Also, within unit test environments, the individual modules of a product become isolated from one another and have their area of responsibility.
- In this scenario, tests are more reliable because they are run in a contained environment. The code, too, because of said reliability, becomes reliable.
Along with the above facts, let’s explore the various benefits of unit tests.
Benefits of Unit Tests
The main advantage of unit tests is their laser-sharp focus. Since they test a single function, they give precise feedback. If a unit test fails, in most cases, testers can be sure that the specific function being tested is the problem.
- Unit tests help to find and fix bugs quickly and easily.
- Unit tests contribute to higher code quality.
- Unit tests contribute to better application architecture.
- Unit tests act as documentation.
Unit tests are also known for their speed. Since they’re fast, they’re executed more often, making them a source of nearly constant valuable feedback.
Best Practices for creating Unit Tests
The following best practices should be followed when creating unit tests:
- Tests should be fast and simple, meaning developers need the test cases to be run at a higher speed as it serves the purpose of unit testing. If they are slow, developers won’t run the test cases as often as they should. Also, the simpler the unit test cases, the more accurate the test results.
- Test cases should not duplicate the implementation logic.
- Test cases should be deterministic – exhibit the same behavior as long as their code is unchanged.
- QAs must execute tests on real browsers and devices, not emulators and simulators to keep tests deterministic. Without exposure to actual production environments (real, functional real devices), test results will be nowhere close to deterministic or accurate.
- Adapt an influential naming convention for the test cases
Read More: Best Practices for Unit Testing
Javascript Unit Testing Frameworks
- JavaScript Unit Testing is a method in which JavaScript test code is written for a web page or application module.
- It is then combined with HTML as an inline event handler and executed in the browser to test if all functionalities work as desired. These unit tests are then organized in the test suite.
The following JavaScript Testing Frameworks are helpful for unit testing in JavaScript. They are as follows:
1. Unit.js
An assertion library for Javascript runs on Node.js and the browser. It works with any test runner and unit testing framework like Mocha, Jasmine, Karma, protractor (E2E test framework for Angular apps), QUnit, etc.
2. Mocha
Mocha is a test framework running both in Node.js and in the browser. This framework makes asynchronous testing simple by running tests serially. Mocha tests run serially, allowing for flexible and accurate reporting while mapping uncaught exceptions to the correct test case. It provides support for all browsers, including the headless Chrome library and is convenient for the developers to write test cases
3. Jest
It is an open-source testing framework built on JavaScript, designed majorly to work with React and React Native-based web applications. Often, unit tests are not very useful when run on the front end of any software. This is mostly because unit tests for the front end require extensive, time-consuming configuration. This complexity can be reduced to a great extent with the Jest framework.
4. Jasmine
Jasmine is a popular JavaScript behavior-driven development framework for unit testing JavaScript applications. It provides utilities that run automated tests for both synchronous and asynchronous code. It is also highly beneficial for front-end testing.
Follow-Up Read: Jest vs Mocha vs Jasmine
5. Karma
Karma is a node-based test tool allowing you to test your JavaScript codes across multiple browsers. It makes test-driven development fast, fun, and easy and is termed as a test-runner technically.
6. Cypress
Cypress framework is a JavaScript-based end-to-end testing framework built on top of Mocha – a feature-rich JavaScript test framework running on and in the browser, making asynchronous testing simple and convenient Unit tests in Cypress are executed without even having to run a web server. That makes Cypress the ideal tool for testing a JS/TS library meant to be used in the browser.
7. NightwatchJS
Nightwatch.js framework is a Selenium-based test automation framework written in Node.js and uses the W3C WebDriver API (formerly Selenium WebDriver). It communicates over a restful HTTP API with a WebDriver server (such as ChromeDriver or Selenium Server). The protocol is defined by the W3C WebDriver spec, which is derived from the JSON Wire protocol.
It is a complete end-to-end testing solution that aims to simplify writing automated tests.
How to choose from JavaScript Unit Testing frameworks?
When it comes to choosing a JavaScript framework for unit testing, consider these key factors:
- Purpose and scope: First, consider the purpose and scope of your project. Are you building a large, complex application or a smaller, simpler one? What types of tests do you need to run? Different frameworks may be better suited for different types of projects and testing needs.
- Ease of use: Consider how easy the framework is to set up, learn, and use. If your team is new to unit testing, you may want to choose a framework that has a lower learning curve.
- Integration with other tools: Look for a framework that integrates well with other tools and technologies you may be using, such as continuous integration tools, code coverage tools, and so on.
- Community and support: Consider the size and activity of the framework’s society and the level of support and documentation available.
- Performance and speed: Finally, consider the implementation and speed of the framework, as this can affect how quickly your tests run and how quickly you can get feedback on code changes.
Writing a Test Case
Here, we’ll be using the Jest tool and testing framework. This tool is one of the de-facto testing tools available, popular because of its ease of use and different testing functionalities. If you are unaware of the Jest configuration, pause here, read this Jest Framework tutorial, and resume with the next steps.
Prerequisites for writing a test case:
Below are some of the libraries and packages required to be installed on the system to run Jest test scripts.
- NodeJS and Node Package Manager (npm): NodeJS can be installed using the npm manager or directly using the Windows Installer binary from the nodejs.org website here.
- Jest Configuration
- Suitable Browser Driver
Now, consider a simple implementation. Here, let’s write a simple pseudo-code for a unit test case. Let’s take a scenario wherein you want to convert the word about-us from English to French in lowercase. The functionality below helps you do the same. Similarly, you can modify the code for multiple other languages as well.
const englishCode = "en-UK"; const germanCode = "de-DE"; function getAboutUsLink(language){ switch (language.toLowerCase()){ case englishCode.toLowerCase(): return '/about-us'; case germanCode.toLowerCase(): return '/über-uns'; } return ''; } module.exports = getAboutUsLink;
Now, let’s put it into the index.js file. Let’s write tests in the same file, but as a good practice, it is better to write separate unit tests into a dedicated file.The common naming patterns include
{filename}.test.js and {filename}.spec.js. This example uses index.test.js:
const getAboutUsLink = require("./index"); test("Return about-us for German language", () => { expect(getAboutUsLink("de-DE")).toBe("/über-uns"); });
Now import the function to be tested. Every test here is defined as an invocation of the test function. The first parameter is the name of the test.
In this case, we call the getAboutUsLink function with en-UK as the language parameter. We expect the result to be /about-us.
Now, invoke the Jest CLI globally and run the test:
npm i jest-cli -g Jest
If you get a configuration-related error, make sure you have your package.json file present. In case you don’t, generate one using npm init.
Your output goes like this:
PASS ./index.test.js √ Returns about-us for english language (4ms) console.log index.js:10 /about-us Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 2.111s
That’s how you write unit test cases using Javascript.
- As far as possible, run tests on real browsers and devices to ensure that software is verified under real user conditions.
- BrowserStack offers a Cloud Selenium Grid of 3000+ real browsers and devices for testing purposes.
- It also offers Cypress testing on 30+ real browser versions. Simply sign up, and choose the required device-browser-OS combination.