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.
Before we start with the fundamentals of testing JavaScript applications, let us briefly understand why it is important.
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
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.
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:
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:
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:
To test JavaScript code, you will need to write test cases that define the expected behavior of your code.
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: