How to test JavaScript applications

Testing is an important part of any development process of an application. It can help build better, more reliable apps. In this blog, we talk about different ways to test JavaScript applications.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

How to test JavaScript applications

Before we start with the fundamentals of testing JavaScript applications, let us briefly understand why it is important.

Why testing your JavaScript applications is important?
  1. Testing helps ensure that your code is correct and behaves as expected.
  2. Testing can help you catch and fix bugs early in the development process.
  3. It can help you refactor your code with confidence as well as you can make changes to your code without worrying about breaking existing functionality.
  4. It improves the quality and reliability of your code.
  5. By writing clear and descriptive test cases, you can create a written record of how your code is supposed to behave.
Ways to test JavaScript applications

1. Unit testing: The way to test small, isolated units of code (such as individual functions), to ensure that they are correct & behaving as expected. Let us understand it in simple terms with an example: Consider you have one function add, it is intended to do the addition of two numbers a+b, but while writing code you have returned a-b by mistake, the function will look like

As a result, when you use this function, it will behave differently, but if you have already written a test for that function, then you can easily notice where the issue is, and this process is called Test-driven development where tests are written for new code before the code itself is written.
Now you know why you should write tests, let us try to write the test for this additional function, in simple words

If you run this code in a JS file let's say node math.js, you will get this error, and you can inspect the same and fix it.

So this is how we can test individual functions and inspect where the issue is, this is known as unit testing.

2. Integration testing: This involves testing the interactions between different units of code, to ensure that they are working correctly together. Let us understand with an example, now we have to add as well as subtract function.

If you run this with node math.js you will get to see. ✔️Test passed successfully.

Now if you notice this test carefully, we are checking interactions between two different units of code which are added and subtracted, and the expected result is based on both functions, hence this is called integration testing.

3. End-to-end testing: This is an interesting way to test the entire application from the user's perspective, simulating the user's interactions with the application and ensuring that the application is functioning correctly. Let us understand this in simple words, now you have the same function for adding two numbers but now you have the UI, which looks like this and is hosted on your localhost (http://localhost:3000)

Let us take a look at what all steps are needed from the user’s perspective to manually test this application

  • Start the browser
  • Open this page (http://localhost:3000)
  • Click on the first input, i.e., a
  • Start typing any number. In this example, it is 3
  • Click on the second input, i.e.,  b
  • Start typing any number. In this example, it is 7
  • Click on submit button
  • Check the answer and conclude whether it is correct or not.

This is known as end-to-end testing, this is a manual thing that can automate all these interactions using the puppeteer & cypress library which is the best choice for end-to-end testing.

4. Snapshot testing: As the name describes, taking a snapshot of the application's state at a particular point in time, and then comparing this snapshot to the application's state at a later point in time to ensure that it has not changed unexpectedly. The testing libraries create a serializable value of the components and store it in a JSON file. The test will be passed if the rendered component matches the snapshot, and fail if the rendered component has changed in any way. Let us try to understand the above sentence with a simple example: You have one function component, which returns HTML markup.

We are using the JSdom library to create a document in a node environment, Now we will create a snapshot of this component & will store this in the __snapshot__ directory with the help of the fs module of the node.
Along with that, we wrote the testSnapshot method which will check if a snapshot of the rendered component is present or not, if not present it will create the snapshot, if the snapshot is already present, then it will check whether it is similar to that of the already created one if it is similar then we are good test will be passed and if not similar our test will be failed.
The code looks like below. To test this code, just add the JSdom package in dependency and create the __snapshot__ directory.

1) If you run this code, in the terminal you will see the message Test "my-test" passed: snapshot created & snapshot will look like below.

2) If you run this code, in the terminal you will see the message Test "my-test" passed.

3) Now if you change the component markup (Intentionally or Unintentionally ) from this "<p>Hello, world! </p>"; to "<p>Hello, world!, It is 2023 </p>"; and run again, you will see the test will failed with the message Test "my-test" failed: rendered component does not match the snapshot

This reason is a snapshot which is already present doesn't match the current snapshot

This is the way how snapshot testing works, but if you have changed the component intentionally then you need to delete the old snapshot and update it with the new one so that subsequent tests won’t be failed.

With these examples, we used JS to elaborate testing methods, but they're way more structured code already created by some libraries for us to use, which are available for testing JavaScript applications, which includes Jest, Mocha, Enzyme, Cypress, etc.

These tools provide a wide range of features and functionality to help you write & run tests for your application. Let’s see them in detail and you can choose the one which you think can be good to go for your requirements.

Popular Testing Libraries:
1. Jest

Jest is a popular JavaScript testing framework that is widely used for unit & integration testing. It is developed and maintained by Facebook, and is often used with the React JavaScript library for testing React components.

Some of the key features of Jest include:

  • Automatic mocking: Jest can automatically mock dependencies for your tests, allowing you to focus on testing the functionality of your code.
  • Snapshot testing: Jest includes a snapshot testing feature that allows you to capture the state of your application at a particular point in time, and then compare it to the state at a later point to ensure that it has not changed unexpectedly.
  • Parallel testing: Jest can run your tests in parallel, which can significantly reduce the time it takes to run your test suite.
  • Code coverage reporting: Jest can generate code coverage reports that show you which lines of your code are being executed during your tests, helping you to identify areas of your code that are not being tested.
2. Mocha

Mocha is a JavaScript testing framework that is widely used for the unit as well as integration testing. It is a flexible and feature-rich framework that provides a wide range of features to help you write and run your tests.

Some of the key features of Mocha include:

  • Asynchronous testing: Mocha allows you to write asynchronous tests, making it a good choice for testing code that involves network requests or other asynchronous operations.
  • Browsers and servers: Mocha can be used to test both browser-based applications and server-side code, making it a versatile choice for testing a wide range of applications.
  • Test reporters: Mocha includes a variety of built-in test reporters, or you can use a third-party reporter to generate test reports in the format of your choice.
  • Extensibility: Mocha is highly extensible, allowing you to use a wide range of plugins and extensions to customize its behavior and add new features.
3. Cypress

Cypress is an end-to-end testing framework for web applications. It is designed to be easy to use and provides a powerful and flexible platform for testing your application's functionality.

Some of the key features of Cypress include:

  • Real-time reloading: Cypress automatically reloads the application whenever a change is made, allowing you to see the changes in real time as you write your tests.
  • Automatic waiting: Cypress automatically waits for elements to become available before interacting with them, eliminating the need to manually add waits or sleeps to your tests.
  • Debugging: Cypress provides an interactive debugger that allows you to step through your tests and examine the state of the application at each step.
  • Network traffic control: Cypress allows you to control the network traffic of your application, including the ability to stub responses to network requests.

To test JavaScript code, you will need to write test cases that define the expected behavior of your code.

4. Enzyme

Enzyme is a JavaScript testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output. It can be used with a test runner such as Jest and allows you to test the behavior of your React components in a more efficient.

Some of the key features of Enzyme include:

  • Shallow rendering: Enzyme allows you to perform a shallow render of a component, which means that you can test the component in isolation without rendering its children.
  • Full rendering: Enzyme also allows you to perform a full render of a component, including its children, which is useful for testing the component's integration with its children.
  • DOM manipulation: Enzyme provides a simple API for manipulating the DOM, allowing you to change the state of a component and verify that it is being rendered correctly.
  • Easy assertion syntax: Enzyme provides a simple and intuitive assertion syntax that makes it easy to write tests for your React components.

Hi, I am Sahil Sukhwani. I am a tech-savvy software developer with a passion for creating groundbreaking products, continuously learning & evolving so that I can turn my ideas into reality.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.